/**************************************************************************** ** ** 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 ** ** This file implements the part of the deep thought package which deals ** with computing the deep thought polynomials. ** ** Deep Thought deals with trees. A tree <tree> is a concatenation of ** several nodes where each node is a 5-tuple of immediate integers. If ** <tree> is an atom it contains only one node, thus it is itself a ** 5-tuple. If <tree> is not an atom we obtain its list representation by ** ** <tree> := topnode(<tree>) concat left(<tree>) concat right(<tree>) . ** ** Let us denote the i-th node of <tree> by (<tree>, i) and the tree rooted ** at (<tree>, i) by tree(<tree>, i). Let <a> be tree(<tree>, i) ** The first entry of (<tree>, i) is pos(a), ** and the second entry is num(a). The third entry of (<tree>, i) gives a ** mark.(<tree>, i)[3] = 1 means that (<tree>, i) is marked, ** (<tree>, i)[3] = 0 means that (<tree>, i) is not marked. The fourth entry ** of (<tree>, i) contains the number of knodes of tree(<tree>, i). The ** fifth entry of (<tree>, i) finally contains a boundary for ** pos( tree(<tree>, i) ). (<tree>, i)[5] <= 0 means that ** pos( tree(<tree>, i) ) is unbounded. If tree(<tree>, i) is an atom we ** already know that pos( tree(<tree>, i) ) is unbound. Thus we then can ** use the fifth component of (<tree>, i) to store the side. In this case ** (<tree>, i)[5] = -1 means that tree(<tree>, i) is an atom from the ** right hand word, and (<tree>, i)[5] = -2 means that tree(<tree>, i) is ** an atom from the left hand word. ** ** A second important data structure deep thought deals with is a deep ** thought monomial. A deep thought monomial g_<tree> is a product of ** binomial coefficients with a coefficient c. Deep thought monomials ** are represented in this implementation by formula ** vectors, which are lists of integers. The first entry of a formula ** vector is 0, to distinguish formula vectors from trees. The second ** entry is the coefficient c, and the third and fourth entries are ** num( left(tree) ) and num( right(tree) ). The remaining part of the ** formula vector is a concatenation of pairs of integers. A pair (i, j) ** with i > 0 represents binomial(x_i, j). A pair (0, j) represents ** binomial(y_gen, j) when word*gen^power is calculated. ** ** Finally deep thought has to deal with pseudorepresentatives. A ** pseudorepresentative <a> is stored in list of length 4. The first entry ** stores left( <a> ), the second entry contains right( <a> ), the third ** entry contains num( <a> ) and the last entry finally gives a boundary ** for pos( <b> ) for all trees <b> which are represented by <a>.
*/
staticvoid UnmarkTree(Obj z); static UInt Mark(Obj tree, Obj reftree, Int indexx); staticInt AlmostEqual(Obj tree1, Int index1, Obj tree2, Int index2); staticInt Equal(Obj tree1, Int index1, Obj tree2, Int index2); static Obj Mark2(Obj tree, Int index1, Obj reftree, Int index2); static UInt FindTree(Obj tree, Int indexx); static Obj MakeFormulaVector(Obj tree, Obj pr); staticInt Leftof(Obj tree1, Int index1, Obj tree2, Int index2); staticInt Leftof2(Obj tree1, Int index1, Obj tree2, Int index2); staticInt Earlier(Obj tree1, Int index1, Obj tree2, Int index2); staticvoid FindNewReps(Obj tree, Obj reps, Obj pr, Obj max); staticvoid FindSubs(Obj tree, Int x,
Obj list1,
Obj list2,
Obj a,
Obj b, Int al, Int ar, Int bl, Int br,
Obj reps,
Obj pr,
Obj max); staticvoid SetSubs(Obj list, Obj a, Obj tree); staticvoid UnmarkAEClass(Obj tree, Obj list);
#ifdef TEST_TREE staticvoid TestTree(Obj tree); static Obj Part(Obj list, Int pos1, Int pos2); #endif
/**************************************************************************** ** *F DT_POS(tree, index) . . . . . . . . . . . . . position of (<tree>, index) ** ** 'DT_POS' returns pos(<a>) where <a> is the subtree of <tree> rooted at ** (<tree>, index). <index> has to be a positive integer less or equal than ** the number of nodes of <tree>.
*/ #define DT_POS(tree, index) \
(ELM_PLIST(tree, (index-1)*5 + 1 ) )
/*************************************************************************** ** *F SET_DT_POS(tree, index, obj) . . . assign the position of(<tree>, index) ** ** 'SET_DT_POS sets pos(<a>) to the object <obj>, where <a> is the subtree ** of <tree>, rooted at (<tree>, index). <index> has to be a positive ** integer less or equal to the number of nodes of <tree>
*/ #define SET_DT_POS(tree, index, obj) \
SET_ELM_PLIST(tree, (index-1)*5 + 1, obj)
/*************************************************************************** ** *F DT_GEN(tree, index) . . . . . . . . . . . . . generator of (<tree>, index) ** ** 'DT_GEN' returns num(<a>) where <a> is the subtree of <tree> rooted at ** (<tree>, index). <index> has to be a positive integer less or equal than ** the number of nodes of <tree>.
*/ #define DT_GEN(tree, index) \
(ELM_PLIST(tree, (index-1)*5 + 2) )
/************************************************************************** ** *F DT_IS_MARKED(tree, index) . . . . . . tests if (<tree>, index) is marked ** ** 'DT_IS_MARKED' returns 1 (as C integer) if (<tree>, index) is marked, and ** 0 otherwise. <index> has to be a positive integer less or equal to the ** number of nodes of <tree>.
*/ #define DT_IS_MARKED(tree, index) \
(INT_INTOBJ (ELM_PLIST(tree, (index-1)*5 + 3) ) )
/************************************************************************** ** *F DT_MARK(tree, index) . . . . . . . . . . . . . . . . . . . . mark a node ** ** 'DT_MARK' marks the node (<tree>, index). <index> has to be a positive ** integer less or equal to the number of nodes of <tree>.
*/ #define DT_MARK(tree, index) \
SET_ELM_PLIST(tree, (index-1)*5 + 3, INTOBJ_INT(1) )
/************************************************************************** ** *F DT_UNMARK(tree, index) . . . . . . . . . . . remove the mark from a node ** ** 'DT_UNMARK' removes the mark from the node (<tree>, index). <index> has ** has to be a positive integer less or equal to the number of nodes of ** <tree>.
*/ #define DT_UNMARK(tree, index) \
SET_ELM_PLIST(tree, (index-1)*5 + 3, INTOBJ_INT(0) )
/**************************************************************************** ** *F DT_RIGHT(tree, index) . . . .determine the right subnode of (<tree>, index) *F DT_LEFT(tree, index) . . . . determine the left subnode of (<tree>, index) ** ** 'DT_RIGHT' returns the right subnode of (<tree>, index). That means if ** DT_RIGHT(tree, index) = index2, then (<tree>, index2) is the right ** subnode of (<tree>, index). ** ** 'DT_LEFT' returns the left subnode of (<tree>, index). That means if ** DT_LEFT(tree, index) = index2, then (<tree>, index2) is the left ** subnode of (<tree>, index). ** ** Before calling 'DT_RIGHT' or 'DT_LEFT' it should be ensured, that ** (<tree>, index) is not an atom. <index> has to be a positive integer ** less or equal to the number of nodes of <tree>.
*/ #define DT_RIGHT(tree, index) \
( INT_INTOBJ(ELM_PLIST(tree, index*5 + 4) ) + index + 1) #define DT_LEFT(tree, index) \
( index + 1 )
/**************************************************************************** ** *F DT_SIDE(tree, index) . . . . . . . determine the side of (<tree>, index) *V RIGHT. . . . . . . . . . . . . . . integer describing "right" *V LEFT . . . . . . . . . . . . . . . integer describing "left" ** ** 'DT_SIDE' returns 'LEFT' if (<tree>, index) is an atom from the Left-hand ** word, and 'RIGHT' if (<tree>, index) is an atom of the Right-hand word. ** Otherwise 'DT_SIDE' returns an integer bigger than 1. <index> has to be ** a positive integer less or equal to the number of nodes of <tree>.
*/ #define RIGHT -1 #define LEFT -2 #define DT_SIDE(tree, index) \
(INT_INTOBJ( ELM_PLIST(tree, (index-1)*5 + 5 ) ) )
/**************************************************************************** ** *F DT_LENGTH(tree, index) . . . . . . . . number of nodes of (<tree>, index) ** ** 'DT_LENGTH' returns the number of nodes of (<tree>, index). <index> has ** to be a positive integer less or equal to the number of nodes of <tree>.
*/ #define DT_LENGTH(tree, index) \
( INT_INTOBJ(ELM_PLIST(tree, (index-1)*5 + 4) ) )
/*************************************************************************** ** *F DT_MAX(tree, index) . . . . . . . . . . . . . . . . boundary of a node ** ** 'DT_MAX(tree, index)' returns a boundary for 'DT_POS(tree, index)'. ** 'DT_MAX(tree, index) = 0 ' means that 'DT_POS(tree, index)' is unbound. ** <index> has to be a positive integer less or equal to the number of nodes ** of tree.
*/ #define DT_MAX(tree, index) \
(ELM_PLIST(tree, (index-1)*5 + 5 ) )
/**************************************************************************** ** *F CELM(list, pos) . . . . . . . . . . element of a plain list as C integer ** ** 'CELM' returns the <pos>-th element of the plain list <list>. <pos> has ** to be a positive integer less or equal to the physical length of <list>. ** Before calling 'CELM' it should be ensured that the <pos>-th entry of ** <list> is an immediate integer object.
*/ #define CELM(list, pos) ( INT_INTOBJ(ELM_PLIST(list, pos) ) )
/**************************************************************************** ** *V Dt_add ** ** Dt_add is used to store the library function dt_add.
*/
static Obj Dt_add;
/**************************************************************************** ** *F UnmarkTree( <tree> ) . . . . . . . remove the marks of all nodes of <tree> ** ** 'UnmarkTree' removes all marks of all nodes of the tree <tree>.
*/ staticvoid UnmarkTree(Obj tree)
{
UInt i, len; // loop variable
len = DT_LENGTH(tree, 1); for (i=1; i <= len; i++ )
DT_UNMARK(tree, i);
}
/**************************************************************************** ** *F FuncUnmarkTree(<self>, <tree>) . . remove the marks of all nodes of <tree> ** ** 'FuncUnmarkTree' implements the internal function 'UnmarkTree'. ** ** 'UnmarkTree( <tree> )' ** ** 'UnmarkTree' removes all marks of all nodes of the tree <tree>.
*/ static Obj FuncUnmarkTree(Obj self, Obj tree)
{
UnmarkTree(tree); return 0;
}
/***************************************************************************** ** *F Mark(<tree>, <reftree>, <index>) . . . . . . . . find all nodes of <tree> ** which are almost equal ** to (<reftree>, index) ** ** 'Mark' determines all nodes of the tree <tree>, rooting subtrees almost ** equal to the tree rooted at (<reftree>, index). 'Mark' marks these nodes ** and returns the number of different nodes among these nodes. Since it ** is assumed that the set {pos(a) | a almost equal to (<reftree>, index) } ** is equal to {1,...,n} for a positive integer n, 'Mark' actually returns ** the Maximum of {pos(a) | a almost equal to (<reftree>, index)}.
*/ static UInt Mark(Obj tree, Obj reftree, Int indexx)
{
UInt i, // loop variable
m, // integer to return
len;
Obj refgen;
m = 0;
i = 1;
len = DT_LENGTH(tree, 1);
refgen = DT_GEN(reftree, indexx); while ( i <= len )
{ /* skip all nodes (<tree>, i) with
** num(<tree>, i) > num(<reftree>, indexx) */ while( i < len &&
DT_GEN(tree, i) > refgen )
i++; if ( AlmostEqual(tree, i, reftree, indexx) )
{
DT_MARK(tree, i); if ( m < INT_INTOBJ( DT_POS(tree, i) ) )
m = INT_INTOBJ( DT_POS(tree, i) );
} /* Since num(a) < num(b) holds for all subtrees <a> of an arbitrary ** tree <b> we can now skip the whole tree rooted at (<tree>, i). ** If (<tree>, i) is the left subnode of another node we can even ** skip the tree rooted at that node, because of ** num( right(a) ) < num( left(a) ) for all trees <a>. ** Note that (<tree>, i) is the left subnode of another node, if and ** only if the previous node (<tree>, i-1) is not an atom. in this
** case (<tree>, i) is the left subnode of (<tree>, i-1). */ if ( DT_LENGTH(tree, i-1) == 1 ) // skip the tree rooted at (<tree>, i).
i = i + DT_LENGTH(tree, i); else // skip the tree rooted at (<tree>, i-1)
i = i - 1 + DT_LENGTH(tree, i-1);
} return m;
}
/**************************************************************************** ** *F AmostEqual(<tree1>,<index1>,<tree2>,<index2>) . . test of almost equality ** ** 'AlmostEqual' tests if tree(<tree1>, index1) is almost equal to ** tree(<tree2>, index2). 'AlmostEqual' returns 1 ** if these trees are almost equal, and 0 otherwise. <index1> has to be ** a positive integer less or equal to the number of nodes of <tree1>, ** and <index2> has to be a positive integer less or equal to the number of ** nodes of <tree2>.
*/ staticInt AlmostEqual(Obj tree1, Int index1, Obj tree2, Int index2)
{
UInt k, schranke; // loop variable /* First the two top nodes of tree(<tree1>, index1) and ** tree(<tree2>, index2) (that are (<tree1>, index1) and ** (<tree2, index2) ) are compared by testing the equality of the 2-nd,
** 5-th and 6-th entries the nodes. */ if ( DT_GEN(tree1, index1) != DT_GEN(tree2, index2) ) return 0; if ( DT_SIDE(tree1, index1) != DT_SIDE(tree2, index2) ) return 0; if ( DT_LENGTH(tree1, index1) != DT_LENGTH(tree2, index2) ) return 0; /* For the comparison of the remaining nodes of tree(<tree1>, index1) ** and tree(<tree2>, index2) it is also necessary to compare the first ** entries of the nodes. Note that we know at this point, that ** tree(<tree1>, index1) and tree(<tree2>, index2) have the same number
** of nodes */
schranke = index1 + DT_LENGTH(tree1, index1); for (k = index1 + 1; k < schranke; k++ )
{ if ( DT_GEN(tree1, k) != DT_GEN(tree2, k + index2 - index1 ) ) return 0; if ( DT_POS(tree1, k) != DT_POS(tree2, k + index2 - index1 ) ) return 0; if ( DT_SIDE(tree1, k) !=
DT_SIDE(tree2, k + index2 - index1) ) return 0; if ( DT_LENGTH(tree1, k) != DT_LENGTH(tree2, k + index2 - index1) ) return 0;
} return 1;
}
/***************************************************************************** ** *F Equal(<tree1>,<index1>,<tree2>,<index2>) . . . . . . . . test of equality ** ** 'Equal' tests if tree(<tree1>, index1) is equal to ** tree(<tree2>, index2). 'Equal' returns 1 ** if these trees are equal, and 0 otherwise. <index1> has to be ** a positive integer less or equal to the number of nodes of <tree1>, ** and <index2> has to be a positive integer less or equal to the number of ** nodes of <tree2>.
*/ staticInt Equal(Obj tree1, Int index1, Obj tree2, Int index2)
{
UInt k, schranke; // loop variable
/* Each node of tree(<tree1>, index1) is compared to the corresponding ** node of tree(<tree2>, index2) by testing the equality of the 1-st,
** 2-nd, 5-th and 6-th nodes. */
schranke = index1 + DT_LENGTH(tree1, index1); for (k=index1; k < schranke; k++)
{ if ( DT_GEN(tree1, k) != DT_GEN(tree2, k + index2 - index1 ) ) return 0; if ( DT_POS(tree1, k) != DT_POS(tree2, k + index2 - index1 ) ) return 0; if ( DT_SIDE(tree1, k) !=
DT_SIDE(tree2, k + index2 - index1) ) return 0; if ( DT_LENGTH(tree1, k) != DT_LENGTH(tree2, k + index2 - index1) ) return 0;
} return 1;
}
/**************************************************************************** ** *F Mark2(<tree>,<index1>,<reftree>,<index2>) . . find all subtrees of ** tree(<tree>, index1) which ** are almost equal to ** tree(<reftree>, index2) ** ** 'Mark2' determines all subtrees of tree(<tree>, index1) that are almost ** equal to tree(<reftree>, index2). 'Mark2' marks the top nodes of these ** trees and returns a list of lists <list> such that <list>[i] ** for each subtree <a> of <tree> which is almost equal to ** tree(<reftree>, index2) and for which pos(<a>) = i holds contains an ** integer describing the position of the top node of <a> in <tree>. ** For example <list>[i] = [j, k] means that tree(<tree>, j) and ** tree(<tree>, k) are almost equal to tree(<reftree>, index2) and ** that pos(tree(<tree>, j) = pos(tree(<tree>, k) = i holds. ** ** <index1> has to be a positive integer less or equal to the number of nodes ** of <tree>, and <index2> has to be a positive integer less or equal to ** the number of nodes of <reftree>.
*/ static Obj Mark2(Obj tree, Int index1, Obj reftree, Int index2)
{
UInt i, // loop variable
len;
Obj new,
list, // list to return
refgen;
// initialize <list>
list = NEW_PLIST(T_PLIST, 0);
i = index1;
len = index1 + DT_LENGTH(tree, index1) - 1;
refgen = DT_GEN(reftree, index2); while( i <= len )
{ /* skip all nodes (<tree>, i) with
** num(<tree>, i) > num(<reftree>, index) */ while( i < len &&
DT_GEN(tree, i) > refgen )
i++; if ( AlmostEqual(tree, i, reftree, index2) )
{
DT_MARK(tree, i); // if <list> is too small grow it appropriately if ( LEN_PLIST(list) < INT_INTOBJ( DT_POS(tree, i) ) )
{
GROW_PLIST(list, INT_INTOBJ( DT_POS(tree, i) ) );
SET_LEN_PLIST(list, INT_INTOBJ( DT_POS(tree, i) ) );
} /* if <list> has no entry at position pos(tree(<tree>, i)) ** create a new list <new>, assign it to list at position
** pos(tree(<tree>, i)), and add i to <new> */ if ( ELM_PLIST(list, INT_INTOBJ( DT_POS(tree, i) ) ) == 0)
{ new = NewPlistFromArgs(INTOBJ_INT(i));
SET_ELM_PLIST(list, INT_INTOBJ( DT_POS(tree, i) ), new); // tell gasman that list has changed
CHANGED_BAG(list);
} // add i to <list>[ pos(tree(<tree>, i)) ] else
{ new = ELM_PLIST(list, INT_INTOBJ( DT_POS(tree, i) ) );
PushPlist(new, INTOBJ_INT(i) );
}
} /* Since num(a) < num(b) holds for all subtrees <a> of an arbitrary ** tree <b> we can now skip the whole tree rooted at (<tree>, i). ** If (<tree>, i) is the left subnode of another node we can even ** skip the tree rooted at that node, because of ** num( right(a) ) < num( left(a) ) for all trees <a>. ** Note that (<tree>, i) is the left subnode of another node, if and ** only if the previous node (<tree>, i-1) is not an atom. In this
** case (<tree>, i) is the left subnode of (<tree>, i-1). */ if ( DT_LENGTH(tree, i-1) == 1 ) // skip tree(<tree>, i)
i = i + DT_LENGTH(tree, i); else // skip tree(<tree>, i-1)
i = i - 1 + DT_LENGTH(tree, i-1);
} return list;
}
/***************************************************************************** ** *F FindTree(<tree>, <index>) ** ** 'FindTree' looks for a subtree <a> of tree(<tree>, index) such that ** the top node of ** <a> is not marked but all the other nodes of <a> are marked. It is ** assumed that if the top node of a subtree <b> of tree(<tree>, index) ** is marked, all ** nodes of <b> are marked. Hence it suffices to look for a subtree <a> ** of <tree> such that the top node of <a> is unmarked and the left and the ** right node of <a> are marked. 'FindTree' returns an integer <i> such ** that tree(<tree> ,i) has the properties mentioned above. If such a tree ** does not exist 'Findtree' returns 0 (as C integer). Note that this holds ** if and only if tree(<tree>, index) is marked.
*/ static UInt FindTree(Obj tree, Int indexx)
{
UInt i; // loop variable
// return 0 if (<tree>, indexx) is marked if ( DT_IS_MARKED(tree, indexx) ) return 0;
i = indexx; /* loop over all nodes of tree(<tree>, indexx) to find a tree with the
** properties described above. */ while( i < indexx + DT_LENGTH(tree, indexx) )
{ // skip all nodes that are unmarked and rooting non-atoms while( !( DT_IS_MARKED(tree, i) ) && DT_LENGTH(tree, i) > 1 )
i++; /* if (<tree>, i) is unmarked we now know that tree(<tree>, i) is ** an atom and we can return i. Note that an unmarked atom has the
** desired properties. */ if ( !( DT_IS_MARKED(tree, i) ) ) return i; // go to the previous node
i--; /* If the right node of tree(<tree>, i) is marked return i.
** Else go to the right node of tree(<tree>, i). */ if ( DT_IS_MARKED(tree, DT_RIGHT(tree, i) ) ) return i;
i = DT_RIGHT(tree, i);
} return 0;
}
/**************************************************************************** ** *F MakeFormulaVector(<tree>, <pr>) . . . . . . . . . compute the polynomial ** g_<tree> for <tree> ** ** 'MakeFormulaVector' returns the polynomial g_<tree> for a tree <tree> ** and a pc-presentation <pr> of a nilpotent group. This polynomial g_<tree> ** is a product of binomial coefficients with a coefficient c ( see the ** header of this file ). ** ** For the calculation of the coefficient c the top node of <tree> is ignored ** because it can happen that trees are equal except for the top node. ** Hence it suffices to compute the formula vector for one of these trees. ** Then we get the "correct" coefficient for the polynomial for each <tree'> ** of those trees by multiplying the coefficient given by the formula vector ** with c_( num(left(<tree'>)), num(right(<tree'>)); num(<tree'>) ). This ** is also the reason for storing num(left(<tree>)) and num(right(<tree>)) ** in the formula vector. ** ** 'MakeFormulaVector' only returns correct results if all nodes of <tree> ** are unmarked.
*/ static Obj MakeFormulaVector(Obj tree, Obj pr)
{
UInt i, // denominator of a binomial coefficient
j, // loop variable
u; // node index
Obj rel, // stores relations of <pr>
vec, // stores formula vector to return
prod,// stores the product of two integers
gen;
// initialize <vec> and set the first four elements
vec = NewPlistFromArgs(INTOBJ_INT(0), INTOBJ_INT(1),
DT_GEN(tree, DT_LEFT(tree, 1)),
DT_GEN(tree, DT_RIGHT(tree, 1))); /* loop over all almost equal classes of subtrees of <tree> except for
** <tree> itself. */
u = FindTree(tree, 1); while( u > 1 )
{ /* mark all subtrees of <tree> almost equal to tree(<tree>, u) and
** get the number of different trees in this almost equal class */
i = Mark(tree, tree, u); /* if tree(<tree>, u) is an atom from the Right-hand word append
** [ 0, i ] to <vec> */ if ( DT_SIDE(tree, u) == RIGHT )
{
GROW_PLIST(vec, LEN_PLIST(vec)+2);
SET_LEN_PLIST(vec, LEN_PLIST(vec)+2);
SET_ELM_PLIST(vec, LEN_PLIST(vec)-1, INTOBJ_INT(0) );
SET_ELM_PLIST(vec, LEN_PLIST(vec), INTOBJ_INT(i) );
} /* if tree(<tree>, u) is an atom from the Left-hand word append
** [ num(tree(<tree>, u)), i ] to <vec> */ elseif ( DT_SIDE(tree, u) == LEFT)
{
GROW_PLIST(vec, LEN_PLIST(vec)+2);
SET_LEN_PLIST(vec, LEN_PLIST(vec)+2);
SET_ELM_PLIST(vec, LEN_PLIST(vec)-1, DT_GEN(tree, u) );
SET_ELM_PLIST(vec, LEN_PLIST(vec), INTOBJ_INT(i) );
} /* if tree(<tree>, u) is not an atom multiply ** <vec>[2] with binomial(d, i) where
** d = c_(num(left(<tree>,u)), num(right(<tree>,u)); num(<tree>,u)) */ else
{
j = 3;
rel = ELM_PLIST( ELM_PLIST(pr, INT_INTOBJ( DT_GEN(tree,
DT_LEFT(tree, u) ) ) ),
INT_INTOBJ( DT_GEN(tree, DT_RIGHT(tree, u) ) ) );
gen = DT_GEN(tree, u); while ( 1 )
{ if ( ELM_PLIST(rel, j) == gen )
{
prod = ProdInt(ELM_PLIST(vec, 2),
BinomialInt(ELM_PLIST(rel, j+1),
INTOBJ_INT(i) ) );
SET_ELM_PLIST(vec, 2, prod); // tell gasman that vec has changed
CHANGED_BAG(vec); break;
}
j+=2;
}
}
u = FindTree(tree, 1);
} return vec;
}
/************************************************************************** ** *F FuncMakeFormulaVector(<self>,<tree>,<pr>) . . . . . compute the formula ** vector for <tree> ** ** 'FuncMakeFormulaVector' implements the internal function ** 'MakeFormulaVector(<tree>, <pr>)'. ** ** 'MakeFormulaVector(<tree>, <pr>)' ** ** 'MakeFormulaVector' returns the formula vector for the tree <tree> and ** the pc-presentation <pr>.
*/ static Obj FuncMakeFormulaVector(Obj self, Obj tree, Obj pr)
{ if (LEN_PLIST(tree) == 5)
ErrorMayQuit(" has to be a non-atom", 0, 0); return MakeFormulaVector(tree, pr);
}
/**************************************************************************** ** *F Leftof(<tree1>,<index1>,<tree2>,<index2>) . . . . test if one tree is left ** of another tree ** ** 'Leftof' returns 1 if tree(<tree1>, index1) is left of tree(<tree2>,index2) ** in the word being collected at the first instance, that ** tree(<tree1>, index1) and tree(<tree2>, index2) both occur. It is assumed ** that tree(<tree1>, index1) is not equal to tree(<tree2>, index2).
*/ staticInt Leftof(Obj tree1, Int index1, Obj tree2, Int index2)
{ if ( DT_LENGTH(tree1, index1) == 1 && DT_LENGTH(tree2, index2) == 1 ) { if (DT_SIDE(tree1, index1) == LEFT && DT_SIDE(tree2, index2) == RIGHT) return 1; elseif (DT_SIDE(tree1, index1) == RIGHT &&
DT_SIDE(tree2, index2) == LEFT ) return 0; elseif (DT_GEN(tree1, index1) == DT_GEN(tree2, index2) ) return ( DT_POS(tree1, index1) < DT_POS(tree2, index2) ); else return ( DT_GEN(tree1, index1) < DT_GEN(tree2, index2) );
} if ( DT_LENGTH(tree1, index1) > 1 &&
DT_LENGTH(tree2, index2) > 1 &&
Equal( tree1, DT_RIGHT(tree1, index1) ,
tree2, DT_RIGHT(tree2, index2) ) )
{ if ( Equal( tree1, DT_LEFT(tree1, index1),
tree2, DT_LEFT(tree2, index2) ) ) { if ( DT_GEN(tree1, index1) == DT_GEN(tree2, index2) ) return ( DT_POS(tree1, index1) < DT_POS(tree2, index2) ); else return ( DT_GEN(tree1, index1) < DT_GEN(tree2, index2) );
}
} if( Earlier(tree1, index1, tree2, index2) ) return !Leftof2( tree2, index2, tree1, index1); else return Leftof2( tree1, index1, tree2, index2);
}
/***************************************************************************** ** *F Leftof2(<tree1>,<index1>,<tree2>,<index2>) . . . . . test if one tree is ** left of another tree ** ** 'Leftof2' returns 1 if tree(<tree1>, index1) is left of ** tree(<tree2>,index2)in the word being collected at the first instance, ** that tree(<tree1>, index1) and tree(<tree2>, index2) both occur. It is ** assumed that tree(<tree2>, index2) occurs earlier than ** tree(<tree1>,index1). Furthermore it is assumed that if both ** tree(<tree1>, index1) and tree(<tree2>, index2) are non-atoms, then their ** right trees and their left trees are not equal.
*/ staticInt Leftof2(Obj tree1, Int index1, Obj tree2, Int index2)
{ if ( DT_GEN(tree2, index2) < DT_GEN(tree1, DT_RIGHT(tree1, index1) ) ) return 0; elseif (Equal(tree1, DT_RIGHT(tree1, index1), tree2, index2 ) ) return 0; elseif (DT_GEN(tree2, index2) == DT_GEN(tree1, DT_RIGHT(tree1, index1)) ) return Leftof(tree1, DT_RIGHT(tree1, index1), tree2, index2 ); elseif (Equal(tree1, DT_LEFT(tree1, index1), tree2, index2) ) return 0; else return Leftof(tree1, DT_LEFT(tree1, index1), tree2, index2);
}
/**************************************************************************** ** *F Earlier(<tree1>,<index1>,<tree2>,<index2>) . . . test if one tree occurs ** earlier than another ** ** 'Earlier' returns 1 if tree(<tree1>, index1) occurs strictly earlier than ** tree(<tree2>, index2). It is assumed that at least one of these trees ** is a non-atom. Furthermore it is assumed that if both of these trees are ** non-atoms, right(tree(<tree1>, index1) ) does not equal ** right(tree(<tree2>, index2) ) or left(tree(<tree1>, index1) ) does not ** equal left(tree(<tree2>, index2) ).
*/ staticInt Earlier(Obj tree1, Int index1, Obj tree2, Int index2)
{ if ( DT_LENGTH(tree1, index1) == 1 ) return 1; if ( DT_LENGTH(tree2, index2) == 1 ) return 0; if ( Equal(tree1, DT_RIGHT(tree1, index1),
tree2, DT_RIGHT(tree2, index2) ) ) return Leftof(tree1, DT_LEFT(tree2, index2),
tree2, DT_LEFT(tree1, index1) ); if ( DT_GEN(tree1, DT_RIGHT(tree1, index1) ) ==
DT_GEN(tree2, DT_RIGHT(tree2, index2) ) ) return Leftof( tree1, DT_RIGHT(tree1, index1) ,
tree2, DT_RIGHT(tree2, index2) ); return (DT_GEN(tree1, DT_RIGHT(tree1, index1) ) <
DT_GEN(tree2, DT_RIGHT(tree2, index2) ) );
}
/**************************************************************************** ** ** GetPols( <list>, <pr>, <pols> ) ** ** GetPols computes all representatives which are represented by the ** pseudorepresentative <list>, converts them all into the corresponding ** deep thought monomial and stores all these monomials in the list <pols>.
*/
lreps = NEW_PLIST(T_PLIST, 2);
rreps = NEW_PLIST(T_PLIST, 2); /* get the representatives that are represented by <list>[1] and those
** which are represented by <list>[2]. */
GetReps( ELM_PLIST(list, 1), lreps );
GetReps( ELM_PLIST(list, 2), rreps );
lenr = LEN_PLIST(rreps);
lenl = LEN_PLIST(lreps); for (i=1; i<=lenl; i++) for (j=1; j<=lenr; j++)
{ /* now get all representatives, which can be constructed from ** <lreps>[<i>] and <rreps>[<j>] and add the corresponding
** deep thought monomials to <pols> */
k = LEN_PLIST( ELM_PLIST(lreps, i) )
+ LEN_PLIST( ELM_PLIST(rreps, j) ) + 5;/* m"ogliche Inkom-*/
tree = NEW_PLIST(T_PLIST, k); /* patibilit"at nach*/
SET_LEN_PLIST(tree, k); /*"Anderung der Datenstruktur */
SET_ELM_PLIST(tree, 1, INTOBJ_INT(1) );
SET_ELM_PLIST(tree, 2, ELM_PLIST( list, 3) );
SET_ELM_PLIST(tree, 3, INTOBJ_INT(0) );
SET_ELM_PLIST(tree, 4, INTOBJ_INT((int)(k/5)) );
SET_ELM_PLIST(tree, 5, INTOBJ_INT(0) );
tree1 = ELM_PLIST(lreps, i);
len = LEN_PLIST( tree1 ); for (l=1; l<=len; l++)
SET_ELM_PLIST(tree, l+5, ELM_PLIST(tree1, l) );
k = LEN_PLIST(tree1) + 5;
tree1 = ELM_PLIST(rreps, j);
len = LEN_PLIST( tree1 ); for (l=1; l<=len; l++)
SET_ELM_PLIST(tree, l+k, ELM_PLIST(tree1, l) );
UnmarkTree(tree);
FindNewReps2(tree, pols, pr);
}
}
/**************************************************************************** ** *F FuncGetPols( <self>, <list>, <pr>, <pols> ) ** ** FuncGetPols implements the internal function GetPols.
*/
static Obj FuncGetPols(Obj self, Obj list, Obj pr, Obj pols)
{ if (LEN_PLIST(list) != 4)
ErrorMayQuit(" must be a generalised representative not a tree",
0, 0);
GetPols(list, pr, pols); return (Obj) 0;
}
/**************************************************************************** ** *F GetReps( <list>, <reps> ) ** ** GetReps computes all representatives which are represented by the ** pseudorepresentative <list> and adds them to the list <reps>.
*/
// See below: staticvoid FindNewReps1(Obj tree, Obj reps);
if ( LEN_PLIST(list) != 4 )
{
SET_ELM_PLIST(reps, 1, list);
SET_LEN_PLIST(reps, 1); return;
}
lreps = NEW_PLIST(T_PLIST, 2);
rreps = NEW_PLIST(T_PLIST, 2); /* now get all representatives which are represented by <list>[1] and
** all representatives which are represented by <list>[2]. */
GetReps( ELM_PLIST(list, 1), lreps );
GetReps( ELM_PLIST(list, 2), rreps );
lenl = LEN_PLIST( lreps );
lenr = LEN_PLIST( rreps ); for (i=1; i<=lenl; i++) for (j=1; j<=lenr; j++)
{ /* compute all representatives which can be constructed from
** <lreps>[<i>] and <rreps>[<j>] and add them to <reps>. */
k = LEN_PLIST( ELM_PLIST(lreps, i) )
+ LEN_PLIST( ELM_PLIST(rreps, j) ) + 5;/* m"ogliche Inkom-*/
tree = NEW_PLIST(T_PLIST, k); /* patibilit"at nach*/
SET_LEN_PLIST(tree, k); /*"Anderung der Datenstruktur */
SET_ELM_PLIST(tree, 1, INTOBJ_INT(1) );
SET_ELM_PLIST(tree, 2, ELM_PLIST( list, 3) );
SET_ELM_PLIST(tree, 3, INTOBJ_INT(0) );
SET_ELM_PLIST(tree, 4, INTOBJ_INT((int)(k/5)) ); if ( IS_INTOBJ( ELM_PLIST(list, 4) ) &&
CELM(list, 4) < 100 && CELM(list, 4) > 0 )
SET_ELM_PLIST(tree, 5, ELM_PLIST(list, 4) ); else
SET_ELM_PLIST(tree, 5, INTOBJ_INT(0) );
tree1 = ELM_PLIST(lreps, i);
len = LEN_PLIST( tree1 ); for (l=1; l<=len; l++)
SET_ELM_PLIST(tree, l+5, ELM_PLIST(tree1, l) );
k = LEN_PLIST(tree1) + 5;
tree1 = ELM_PLIST(rreps, j);
len = LEN_PLIST( tree1 ); for (l=1; l<=len; l++)
SET_ELM_PLIST(tree, l+k, ELM_PLIST(tree1, l) );
UnmarkTree(tree);
FindNewReps1(tree, reps);
}
}
/************************************************************************** ** *F FindNewReps(<tree>,<reps>,<pr>,<max>) . . construct new representatives ** ** 'FindNewReps' constructs all trees <tree'> with the following properties. ** 1) left(<tree'>) is equivalent to left(<tree>). ** right(<tree'>) is equivalent to right(<tree>). ** num(<tree'>) = num(<tree>) ** 2) <tree'> is the least tree in its equivalence class. ** 3) for each marked node of (<tree>, i) of <tree> tree(<tree>, i) is equal ** to tree(<tree'>, i). ** There are three versions of FindNewReps. FindNewReps1 adds all found ** trees to the list <reps>. This version is called by GetReps. ** FindNewReps2 computes for each found tree the corresponding deep thought ** monomial adds these deep thought monomials to <reps>. This version ** is called from GetPols. ** The third version FindNewReps finally assumes that <reps> is the list of ** pseudorepresentatives. This Version adds all found trees to <reps> and ** additionally all trees, that fulfill 1), 2) and 3) except for ** num(<tree'>) = num(<tree>). This version is called from the library ** function calrepsn. ** It is assumed that both left(<tree>) and right(<tree>) are the least ** elements in their equivalence class.
*/
// See below: staticvoid FindSubs1(Obj tree, Int x,
Obj list1,
Obj list2,
Obj a,
Obj b, Int al, Int ar, Int bl, Int br,
Obj reps);
staticvoid FindNewReps1(Obj tree, Obj reps)
{
Obj y, // stores a copy of <tree>
lsubs, /* stores pos(<subtree>) for all subtrees of
** left(<tree>) in a given almost equal class */
rsubs, /* stores pos(<subtree>) for all subtrees of
** right(<tree>) in the same almost equal class */
llist, /* stores all elements of an almost equal class
** of subtrees of left(<tree>) */
rlist; /* stores all elements of the same almost equal
** class of subtrees of right(<tree>) */ Int a, // stores a subtree of right((<tree>)
n, // Length of lsubs
m, // Length of rsubs
i; // loop variable
/* get a subtree of right(<tree>) which is unmarked but whose
** subtrees are all marked */
a = FindTree(tree, DT_RIGHT(tree, 1) ); /* If we do not find such a tree we at the bottom of the recursion. ** If leftof(left(<tree>), right(<tree>) ) holds we add all <tree>
** to <reps>. */ if ( a == 0 )
{ if ( Leftof(tree, DT_LEFT(tree, 1), tree, DT_RIGHT(tree, 1) ) )
{
y = ShallowCopyPlist(tree);
AssPlist(reps, LEN_PLIST(reps) + 1, y);
} return;
} /* get all subtrees of left(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
llist = Mark2(tree, DT_LEFT(tree, 1), tree, a); /* get all subtrees of right(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
rlist = Mark2(tree, DT_RIGHT(tree, 1), tree, a);
n = LEN_PLIST(llist);
m = LEN_PLIST(rlist); /* if no subtrees of left(<tree>) almost equal to ** tree(<tree>, a) have been found there is no possibility ** to change the pos-argument in the trees stored in llist and ** rlist, so call FindNewReps without changing any pos-arguments.
*/ if ( n == 0 )
{
FindNewReps1(tree, reps); // unmark all top nodes of the trees stored in rlist
UnmarkAEClass(tree, rlist); return;
} /* store all pos-arguments that occur in the trees of llist. ** Note that the set of the pos-arguments in llist actually
** equals {1,...,n}. */
lsubs = NEW_PLIST( T_PLIST, n );
SET_LEN_PLIST(lsubs, n); for (i=1; i<=n; i++)
SET_ELM_PLIST(lsubs, i, INTOBJ_INT(i) ); /* store all pos-arguments that occur in the trees of rlist. ** Note that the set of the pos-arguments in rlist actually
** equals {1,...,m}. */
rsubs = NEW_PLIST( T_PLIST, m );
SET_LEN_PLIST(rsubs, m); for (i=1; i<=m; i++)
SET_ELM_PLIST(rsubs, i, INTOBJ_INT(i) ); /* find all possibilities for lsubs and rsubs such that ** lsubs[1] < lsubs[2] <...<lsubs[n], ** rsubs[1] < rsubs[2] <...<rsubs[n], ** and set(lsubs concat rsubs) equals {1,...,k} for a positive ** integer k. For each found lsubs and rsubs 'FindSubs' changes ** pos-arguments of the subtrees in llist and rlist accordingly ** and then calls 'FindNewReps' with the changed tree <tree>.
*/
FindSubs1(tree, a, llist, rlist, lsubs, rsubs, 1, n, 1, m, reps); /* Unmark the subtrees of <tree> in llist and rlist and reset
** pos-arguments to the original state. */
UnmarkAEClass(tree, rlist);
UnmarkAEClass(tree, llist);
}
// See below: staticvoid FindSubs2(Obj tree, Int x,
Obj list1,
Obj list2,
Obj a,
Obj b, Int al, Int ar, Int bl, Int br,
Obj reps,
Obj pr);
staticvoid
FindNewReps2(Obj tree, Obj reps, Obj pr /* pc-presentation for a
** nilpotent group <G> */
)
{
Obj lsubs, /* stores pos(<subtree>) for all subtrees of
** left(<tree>) in a given almost equal class */
rsubs, /* stores pos(<subtree>) for all subtrees of
** right(<tree>) in the same almost equal class */
llist, /* stores all elements of an almost equal class
** of subtrees of left(<tree>) */
rlist; /* stores all elements of the same almost equal
** class of subtrees of right(<tree>) */ Int a, // stores a subtree of right((<tree>)
n, // Length of lsubs
m, // Length of rsubs
i; // loop variable
/* get a subtree of right(<tree>) which is unmarked but whose
** subtrees are all marked */
a = FindTree(tree, DT_RIGHT(tree, 1) ); /* If we do not find such a tree we at the bottom of the recursion. ** If leftof(left(<tree>), right(<tree>) ) holds we convert <tree> ** into the corresponding deep thought monomial and add that to
** <reps>. */ if ( a == 0 )
{ if ( Leftof(tree, DT_LEFT(tree, 1), tree, DT_RIGHT(tree, 1) ) )
{ /* get the formula vector of tree and add it to
** reps[ rel[1] ]. */
UnmarkTree(tree);
tree = MakeFormulaVector( tree, pr);
CALL_3ARGS(Dt_add, tree, reps, pr);
} return;
} /* get all subtrees of left(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
llist = Mark2(tree, DT_LEFT(tree, 1), tree, a); /* get all subtrees of right(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
rlist = Mark2(tree, DT_RIGHT(tree, 1), tree, a);
n = LEN_PLIST(llist);
m = LEN_PLIST(rlist); /* if no subtrees of left(<tree>) almost equal to ** tree(<tree>, a) have been found there is no possibility ** to change the pos-argument in the trees stored in llist and ** rlist, so call FindNewReps without changing any pos-arguments.
*/ if ( n == 0 )
{
FindNewReps2(tree, reps, pr); // unmark all top nodes of the trees stored in rlist
UnmarkAEClass(tree, rlist); return;
} /* store all pos-arguments that occur in the trees of llist. ** Note that the set of the pos-arguments in llist actually
** equals {1,...,n}. */
lsubs = NEW_PLIST( T_PLIST, n );
SET_LEN_PLIST(lsubs, n); for (i=1; i<=n; i++)
SET_ELM_PLIST(lsubs, i, INTOBJ_INT(i) ); /* store all pos-arguments that occur in the trees of rlist. ** Note that the set of the pos-arguments in rlist actually
** equals {1,...,m}. */
rsubs = NEW_PLIST( T_PLIST, m );
SET_LEN_PLIST(rsubs, m); for (i=1; i<=m; i++)
SET_ELM_PLIST(rsubs, i, INTOBJ_INT(i) ); /* find all possibilities for lsubs and rsubs such that ** lsubs[1] < lsubs[2] <...<lsubs[n], ** rsubs[1] < rsubs[2] <...<rsubs[n], ** and set(lsubs concat rsubs) equals {1,...,k} for a positive ** integer k. For each found lsubs and rsubs 'FindSubs' changes ** pos-arguments of the subtrees in llist and rlist accordingly ** and then calls 'FindNewReps' with the changed tree <tree>.
*/
FindSubs2(tree, a, llist, rlist, lsubs, rsubs, 1, n, 1, m, reps, pr); /* Unmark the subtrees of <tree> in llist and rlist and reset
** pos-arguments to the original state. */
UnmarkAEClass(tree, rlist);
UnmarkAEClass(tree, llist);
}
staticvoid FindNewReps(Obj tree,
Obj reps,
Obj pr, /* pc-presentation for a
** nilpotent group <G> */
Obj max /* every generator <g_i> of <G> with
** i > max lies in the center of <G> */
)
{
Obj y, // stores a copy of <tree>
lsubs, /* stores pos(<subtree>) for all subtrees of
** left(<tree>) in a given almost equal class */
rsubs, /* stores pos(<subtree>) for all subtrees of
** right(<tree>) in the same almost equal class */
llist, /* stores all elements of an almost equal class
** of subtrees of left(<tree>) */
rlist, /* stores all elements of the same almost equal
** class of subtrees of right(<tree>) */
list1, // stores a sublist of <reps>
rel; // stores a commutator relation from <pr> Int a; // stores a subtree of right((<tree>)
UInt n, // Length of lsubs
m, // Length of rsubs
i, lenrel; // loop variable
/* get a subtree of right(<tree>) which is unmarked but whose
** subtrees are all marked */
a = FindTree(tree, DT_RIGHT(tree, 1) ); /* If we do not find such a tree we at the bottom of the recursion. ** If leftof(left(<tree>), right(<tree>) ) holds we add all trees ** <tree'> with left(<tree'>) = left(<tree>), ** right(<tree'>) = right(<tree>) to <reps>, and <tree'> is the ** least element in its equivalence class. Note that for such a ** tree we have pos(<tree'>) = 1 and num(<tree'>) = j where j is a ** positive integer for which ** c_( num(left(<tree>), num(right(<tree>)), j ) does not equal ** 0. These integers are contained in the list
** pr[ num(left(<tree>)) ][ num(right(<tree>)) ]. */ if ( a == 0 )
{ if ( Leftof(tree, DT_LEFT(tree, 1), tree, DT_RIGHT(tree, 1) ) )
{ // get pr[ num(left(<tree>)) ][ num(right(<tree>)) ]
rel = ELM_PLIST( ELM_PLIST(pr, INT_INTOBJ( DT_GEN(tree,
DT_LEFT(tree, 1)))) ,
INT_INTOBJ( DT_GEN(tree, DT_RIGHT(tree, 1) ) ) ); if ( ELM_PLIST(rel, 3) > max )
{
UnmarkTree(tree);
tree = MakeFormulaVector(tree, pr);
list1 = ELM_PLIST(reps, CELM(rel, 3) );
PushPlist(list1, tree);
} else
{
y = ShallowCopyPlist(tree);
lenrel = LEN_PLIST(rel); for ( i=3;
i < lenrel &&
ELM_PLIST(rel, i) <= max;
i+=2 )
{
list1 = ELM_PLIST(reps, CELM(rel, i) );
PushPlist(list1, y);
}
}
} return;
} /* get all subtrees of left(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
llist = Mark2(tree, DT_LEFT(tree, 1), tree, a); /* get all subtrees of right(<tree>) which are almost equal to
** tree(<tree>, a) and mark them */
rlist = Mark2(tree, DT_RIGHT(tree, 1), tree, a);
n = LEN_PLIST(llist);
m = LEN_PLIST(rlist); /* if no subtrees of left(<tree>) almost equal to ** tree(<tree>, a) have been found there is no possibility ** to change the pos-argument in the trees stored in llist and ** rlist, so call FindNewReps without changing any pos-arguments.
*/ if ( n == 0 )
{
FindNewReps(tree, reps, pr, max); // unmark all top nodes of the trees stored in rlist
UnmarkAEClass(tree, rlist); return;
} /* store all pos-arguments that occur in the trees of llist. ** Note that the set of the pos-arguments in llist actually
** equals {1,...,n}. */
lsubs = NEW_PLIST( T_PLIST, n );
SET_LEN_PLIST(lsubs, n); for (i=1; i<=n; i++)
SET_ELM_PLIST(lsubs, i, INTOBJ_INT(i) ); /* store all pos-arguments that occur in the trees of rlist. ** Note that the set of the pos-arguments in rlist actually
** equals {1,...,m}. */
rsubs = NEW_PLIST( T_PLIST, m );
SET_LEN_PLIST(rsubs, m); for (i=1; i<=m; i++)
SET_ELM_PLIST(rsubs, i, INTOBJ_INT(i) ); /* find all possibilities for lsubs and rsubs such that ** lsubs[1] < lsubs[2] <...<lsubs[n], ** rsubs[1] < rsubs[2] <...<rsubs[n], ** and set(lsubs concat rsubs) equals {1,...,k} for a positive ** integer k. For each found lsubs and rsubs 'FindSubs' changes ** pos-arguments of the subtrees in llist and rlist accordingly ** and then calls 'FindNewReps' with the changed tree <tree>.
*/
FindSubs(tree, a, llist, rlist, lsubs, rsubs, 1, n, 1, m, reps, pr, max); /* Unmark the subtrees of <tree> in llist and rlist and reset
** pos-arguments to the original state. */
UnmarkAEClass(tree, rlist);
UnmarkAEClass(tree, llist);
}
/*************************************************************************** ** *F FuncFindNewReps(<self>,<args>) . . . . . . construct new representatives ** ** 'FuncFindNewReps' implements the internal function 'FindNewReps'.
*/
#ifdef TEST_TREE // test if <tree> is really a tree
TestTree(tree); #endif if (LEN_PLIST(tree) < 15)
ErrorMayQuit(" must be a tree not a plain list", 0, 0);
FindNewReps(tree, reps, pr, max); return 0;
}
/*************************************************************************** ** *F TestTree(<obj>) . . . . . . . . . . . . . . . . . . . . . . test a tree ** ** 'TestTree' tests if <tree> is a tree. If <tree> is not a tree 'TestTree' ** signals an error.
*/ #ifdef TEST_TREE staticvoid TestTree(
Obj tree)
{ if ( TNUM_OBJ(tree) != T_PLIST || LEN_PLIST(tree) % 7 != 0)
ErrorMayQuit( " must be a plain list, whose length is a multiple of 7",
0, 0); if ( DT_LENGTH(tree, 1) != LEN_PLIST(tree)/7 )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0); if ( DT_SIDE(tree, 1) >= DT_LENGTH(tree, 1) )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0); if ( DT_LENGTH(tree, 1) == 1)
{ if ( DT_SIDE(tree, 1) != LEFT && DT_SIDE(tree, 1) != RIGHT )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0); return;
} if ( DT_SIDE(tree, 1) <= 1 )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0); if (DT_LENGTH(tree, 1) !=
DT_LENGTH(tree, DT_LEFT(tree, 1)) +
DT_LENGTH(tree, DT_RIGHT(tree, 1)) +
1 )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0); if ( DT_SIDE(tree, 1) != DT_LENGTH(tree, DT_LEFT(tree, 1) ) + 1 )
ErrorMayQuit(" must be a tree, not a plain list", 0, 0);
TestTree( Part(tree, (DT_LEFT(tree, 1) - 1)*7,
(DT_RIGHT(tree, 1) - 1)*7 ) );
TestTree( Part(tree, (DT_RIGHT(tree, 1) - 1)*7, LEN_PLIST(tree) ) );
} #endif
/**************************************************************************** ** *F Part(<list>, <pos1>, <pos2>) . . . . . . . . . . . return a part of list ** ** 'Part' returns <list>{ [<pos1>+1 .. <pos2>] }.
*/ #ifdef TEST_TREE static Obj Part(
Obj list, Int pos1, Int pos2 )
{ Int i, length;
Obj part;
length = pos2 - pos1;
part = NEW_PLIST(T_PLIST, length);
SET_LEN_PLIST(part, length); for (i=1; i <= length; i++)
{
SET_ELM_PLIST(part, i, ELM_PLIST(list, pos1+i) );
} return part;
} #endif
/*************************************************************************** ** *F FindSubs(<tree>,<x>,<list1>,<list2>,<a>,<b>,<al>,<ar>,<bl>,<br>,<reps>, ** <pr>,<max> ) . . . . . . . . . find possible pos-arguments for ** the trees in <list1> and <list2> ** ** 'FindSubs' finds all possibilities for a and b such that ** 1) a[1] < a[2] <..< a[ ar ] ** b[1] < b[2] <..< b[ br ] ** 2) set( a concat b ) = {1,..,k} for a positive integer k. ** 3) a[1],...,a[ al-1 ] and b[1],..,b[ bl-1 ] remain unchanged. ** For each found possibility 'FindSubs' sets the pos-arguments in the ** trees of <list1> and <list2> according to the entries of <a> and ** <b>. Then it calls 'FindNewReps' with the changed tree <tree> as v** argument. ** ** It is assumed that the conditions 1) and 2) hold for a{ [1..al-1] } and ** b{ [1..bl-1] }. ** ** There are three versions of FindSubs according to the three versions of ** FindNewReps. FindSubs1 is called from FindNewReps1 and calls ** FindNewReps1. FindSubs2 is called from FindNewReps2 and calls ** FindNewReps2. FindSubs is called from FindNewReps and calls FindNewReps.
*/
staticvoid FindSubs1(Obj tree, Int x, // subtree of <tree>
Obj list1, /* list containing all subtrees of ** left(<tree>) almost equal to
** tree(<tree>, x) */
Obj list2, /* list containing all subtrees of ** right(<tree>) almost equal to
** tree(<tree>, x) */
Obj a, /* list to change, containing the
** pos-arguments of the trees in list1 */
Obj b, /* list to change, containing the
** pos-arguments of the trees in list2 */ Int al, Int ar, Int bl, Int br,
Obj reps // list of representatives for all trees
)
{ Int i; // loop variable
// if <al> > <ar> or <bl> > <br> nothing remains to change. if ( al > ar || bl > br )
{ /* Set the pos-arguments of the trees in <list1> and <list2>
** according to the entries of <a> and <b>. */
SetSubs( list1, a, tree);
SetSubs( list2, b, tree);
FindNewReps1(tree, reps); return;
} /* If a[ ar] is bigger or equal to the boundary of pos(tree(<tree>, x) ** the execution of the statements in the body of this if-statement ** would have the consequence that some subtrees of <tree> in <list1> ** would get a pos-argument bigger than the boundary of ** pos(tree<tree>, x). But since the trees in <list1> are almost ** equal to tree(<tree>, x) they have all the same boundary for their ** pos-argument as tree(<tree>, x). So these statements are only ** executed when <a>[ar] is less than the boundary of ** pos(tree(<tree>, x).
*/ if ( INT_INTOBJ( DT_MAX(tree, x) ) <= 0 ||
ELM_PLIST(a, ar) < DT_MAX(tree, x) )
{ for (i=al; i<=ar; i++)
SET_ELM_PLIST(a, i, INTOBJ_INT( CELM(a,i) + 1 ) );
FindSubs1(tree, x, list1, list2, a, b, al, ar, bl+1, br, reps); for (i=al; i<=ar; i++)
SET_ELM_PLIST(a, i, INTOBJ_INT( CELM(a, i) - 1 ) );
}
FindSubs1(tree, x, list1, list2, a, b, al+1, ar, bl+1, br, reps); /* If b[ br] is bigger or equal to the boundary of pos(tree(<tree>, x) ** the execution of the statements in the body of this if-statement ** would have the consequence that some subtrees of <tree> in <list2> ** would get a pos-argument bigger than the boundary of ** pos(tree<tree>, x). But since the trees in <list2> are almost ** equal to tree(<tree>, x) they have all the same boundary for their ** pos-argument as tree(<tree>, x). So these statements are only ** executed when <b>[br] is less than the boundary of ** pos(tree(<tree>, x).
*/ if ( INT_INTOBJ( DT_MAX(tree, x) ) <= 0 ||
ELM_PLIST(b, br) < DT_MAX(tree, x) )
{ for (i=bl; i<=br; i++)
SET_ELM_PLIST(b, i, INTOBJ_INT( CELM(b, i) + 1 ) );
FindSubs1(tree, x, list1, list2, a, b, al+1, ar, bl, br, reps); for (i=bl; i<=br; i++)
SET_ELM_PLIST(b, i, INTOBJ_INT( CELM(b, i) - 1 ) );
}
}
staticvoid FindSubs2(Obj tree, Int x, // subtree of <tree>
Obj list1, /* list containing all subtrees of ** left(<tree>) almost equal to
** tree(<tree>, x) */
Obj list2, /* list containing all subtrees of ** right(<tree>) almost equal to
** tree(<tree>, x) */
Obj a, /* list to change, containing the
** pos-arguments of the trees in list1 */
Obj b, /* list to change, containing the
** pos-arguments of the trees in list2 */ Int al, Int ar, Int bl, Int br,
Obj reps, // list of representatives for all trees
Obj pr // pc-presentation
)
{ Int i; // loop variable
// if <al> > <ar> or <bl> > <br> nothing remains to change. if ( al > ar || bl > br )
{ /* Set the pos-arguments of the trees in <list1> and <list2>
** according to the entries of <a> and <b>. */
SetSubs( list1, a, tree);
SetSubs( list2, b, tree);
FindNewReps2(tree, reps, pr); return;
} /* If a[ ar] is bigger or equal to the boundary of pos(tree(<tree>, x) ** the execution of the statements in the body of this if-statement ** would have the consequence that some subtrees of <tree> in <list1> ** would get a pos-argument bigger than the boundary of ** pos(tree<tree>, x). But since the trees in <list1> are almost ** equal to tree(<tree>, x) they have all the same boundary for their ** pos-argument as tree(<tree>, x). So these statements are only ** executed when <a>[ar] is less than the boundary of ** pos(tree(<tree>, x).
*/ if ( INT_INTOBJ( DT_MAX(tree, x) ) <= 0 ||
ELM_PLIST(a, ar) < DT_MAX(tree, x) )
{ for (i=al; i<=ar; i++)
SET_ELM_PLIST(a, i, INTOBJ_INT( CELM(a,i) + 1 ) );
FindSubs2(tree, x, list1, list2, a, b, al, ar, bl+1, br, reps, pr); for (i=al; i<=ar; i++)
SET_ELM_PLIST(a, i, INTOBJ_INT( CELM(a, i) - 1 ) );
}
FindSubs2(tree, x, list1, list2, a, b, al+1, ar, bl+1, br, reps, pr); /* If b[ br] is bigger or equal to the boundary of pos(tree(<tree>, x) ** the execution of the statements in the body of this if-statement ** would have the consequence that some subtrees of <tree> in <list2> ** would get a pos-argument bigger than the boundary of ** pos(tree<tree>, x). But since the trees in <list2> are almost ** equal to tree(<tree>, x) they have all the same boundary for their ** pos-argument as tree(<tree>, x). So these statements are only ** executed when <b>[br] is less than the boundary of ** pos(tree(<tree>, x).
*/ if ( INT_INTOBJ( DT_MAX(tree, x) ) <= 0 ||
ELM_PLIST(b, br) < DT_MAX(tree, x) )
{ for (i=bl; i<=br; i++)
SET_ELM_PLIST(b, i, INTOBJ_INT( CELM(b, i) + 1 ) );
FindSubs2(tree, x, list1, list2, a, b, al+1, ar, bl, br, reps, pr); for (i=bl; i<=br; i++)
SET_ELM_PLIST(b, i, INTOBJ_INT( CELM(b, i) - 1 ) );
}
}
staticvoid FindSubs(Obj tree, Int x, // subtree of <tree>
Obj list1, /* list containing all subtrees of ** left(<tree>) almost equal to
** tree(<tree>, x) */
Obj list2, /* list containing all subtrees of ** right(<tree>) almost equal to
** tree(<tree>, x) */
Obj a, /* list to change, containing the
** pos-arguments of the trees in list1 */
Obj b, /* list to change, containing the
** pos-arguments of the trees in list2 */ Int al, Int ar, Int bl, Int br,
Obj reps, // list of representatives for all trees
Obj pr, // pc-presentation
Obj max // needed to call 'FindNewReps'
)
{ Int i; // loop variable
// if <al> > <ar> or <bl> > <br> nothing remains to change. if ( al > ar || bl > br )
{ /* Set the pos-arguments of the trees in <list1> and <list2>
** according to the entries of <a> and <b>. */
SetSubs( list1, a, tree);
SetSubs( list2, b, tree);
FindNewReps(tree, reps, pr, max); return;
} /* If a[ ar] is bigger or equal to the boundary of pos(tree(<tree>, x) ** the execution of the statements in the body of this if-statement ** would have the consequence that some subtrees of <tree> in <list1> ** would get a pos-argument bigger than the boundary of ** pos(tree<tree>, x). But since the trees in <list1> are almost ** equal to tree(<tree>, x) they have all the same boundary for their ** pos-argument as tree(<tree>, x). So these statements are only
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.34 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.