Files
secondo/Algebras/Periodic/RepTree.cpp
2026-01-23 17:03:45 +08:00

688 lines
18 KiB
C++

/*
1. The Repetition Tree (Implementation)
This class realizes a representation of a
repetition-tree. This is a very specialized
tree representing repetitions in a list of integer
values. A node in the tree can be of type simple, composition
or repetition. The content of the node depends on this type. For a
simple type, the content corresponds to the integer number. For a
composite node, the content represents the number of sons in this
node. For a repetition node, the content describes the count of
repetitions.
*/
#include <iostream>
#include <string>
#include <cassert>
#include <stdlib.h>
#include "RepTree.h"
#include "List2.h"
/*
~Defining Types of nodes~
They are three types of nodes. A simple node represents a
leaf containing a integer number as content. A composite node
is a node with at least one son. A repetition node is a node
with exacly one son and the content of this node
defines the count of repetitions of this son.
*/
#include "NodeTypes.h"
namespace periodic {
/*
~ID variable~
Each node in this implementation contains a id. Nodes representing
the same tree will also have the same id. Because the ids are
assigned to the nodes at runtime, it is not possible to make
persistent this kind of trees.
*/
static int lastid = 0;
/*
~Structure for replacement~
For replacing of sons by repetions
we need a structure storing the start and end
index of the sons to be replaced. Furthermore the
repetition node is stored.
*/
struct replacement{
int startindex;
int endindex;
RepTree* replacetree;
};
/*
~Constructor~
This conmtructor creates a single leaf holding the
given value.
*/
RepTree::RepTree(const int content){
this->type = SIMPLE;
this->content = content;
this->id = lastid++;
sons = 0;
}
/*
~Constructor~
This constructor creates a single composite tree from the
given integer list. After that, the detectrepetitions function
is called to build a real repetition tree from the initial
composite node.
*/
RepTree::RepTree(int *content,const int count){
this->type = COMPOSITION;
this->content = count;
this->id = lastid++;
sons = new RepTree*[count];
for(int i=0;i<count;i++)
sons[i] = new RepTree(content[i]);
DetectRepetitions();
}
/*
~Constructor~
This constructor takes a composite, or simple node and
creates a repetition with given count from it. The count is
stored in the content value;
*/
RepTree::RepTree(RepTree* node,const int repetitions){
this->type = REPETITION;
this->content = repetitions;
this->id = lastid++;
sons = new RepTree*[1];
sons[0] = node;
}
/*
~Constructor~
This constructor takes an array of pointers to a tree, a startindex
as well as an endindex and constructs a new composite move from this
informations.
*/
RepTree::RepTree(RepTree** nodes,const int startindex,const int endindex){
this->type = COMPOSITION;
this->content = endindex-startindex+1;
this->id = lastid++;
sons = new RepTree*[content];
for(int i=startindex;i<=endindex;i++)
sons[i-startindex]=nodes[i];
}
/*
~Constructor~
This constructor creates a new repetition node referering to a new
composite node which is created from the nodearray given as the first
argument as well as the index information from the next two arguments.
*/
RepTree::RepTree(RepTree** nodes,const int startindex,
const int endindex,const int repcount){
this->type = REPETITION;
this->content=repcount;
this->id = lastid++;
sons = new RepTree*[1];
sons[0] = new RepTree(nodes,startindex,endindex);
}
/*
~Destroy~
This Function removes all subtrees from this node. This is useful in
deleting a tree.
*/
void RepTree::Destroy(){
if(type==SIMPLE) return;
if(type==REPETITION) delete sons[0];
if(type==COMPOSITION)
for(int i=0;i<content;i++){
sons[i]->Destroy();
delete sons[i];
}
}
/*
~Destructor~
This destructor removes the sons array without touching the
sons themself.
*/
RepTree::~RepTree(){
//delete[] sons;
}
/*
~GetSon~
This function returns the son with the given index.
*/
RepTree* RepTree::GetSon(int index)const{
// determine the maximum possible index
int maxindex=-1; // no son
if(type==REPETITION)
maxindex=0; // a repetition contains exacly one son
if(type==COMPOSITION)
maxindex=content-1;
if((index<0) || (index>maxindex)){
std::cerr << "try to access sons[" << index <<
"] with maximum index of " << maxindex << "\n";
assert(false);
}
return sons[index];
}
/*
~EqualID~
This function checks whether this node and the node given
as argument have the same id.
*/
bool RepTree::EqualID(const RepTree* T2)const{
if(this->type != T2->type)
return false;
if(this->type==SIMPLE){ // use content instead of id
return this->content==T2->content;
}
return this->id == T2->id;
}
/*
~EqualsWithDepth~
This function checks the equality of two tree up to a given length.
At level 0, the trees are only compared via there id's.
*/
bool RepTree::EqualWithDepth(const RepTree* T2, const int depth)const{
if(depth<=0)
return EqualID(T2);
if(this->type != T2->type)
return false;
if(this->type==SIMPLE)
return this->content==T2->content;
if(this->type==REPETITION)
return (this->content==T2->content) &&
this->sons[0]->EqualWithDepth(T2->sons[0],depth-1);
// type is composite
if(this->content!=T2->content)
return false;
bool ok = true;
for(int i=0;i<this->content&&ok;i++) {
ok = this->sons[i]->EqualWithDepth(T2->sons[i],depth-1);
}
return ok;
}
/*
~NumberOfNodes~
This function computes the number of nodes contained in this
(sub-) tree. This can be useful in statistical computations.
*/
int RepTree::NumberOfNodes()const{
if(this->type==SIMPLE)
return 1;
int res = 0;
if(this->type==COMPOSITION)
for(int i=0;i<content;i++)
res += (sons[i])->NumberOfNodes();
if(this->type==REPETITION)
res = sons[0]->NumberOfNodes();
return res+1;
}
/*
~NumberOfLeafs~
This function computes the number of leafs contained in this
(sub-) tree. The ratio between number of leafs before detecting of
repetitions and after this detection is a measure for the success of
this replacement.
*/
int RepTree::NumberOfLeafs()const{
if(this->type==SIMPLE)
return 1;
else if(this->type==REPETITION)
return sons[0]->NumberOfLeafs();
int res = 0;
for(int i=0;i<content;i++)
res += sons[i]->NumberOfLeafs();
return res;
}
/*
~GetNodeType~
This returns the type of this node. Possible values are
SIMPLE, COMPOSITION, and REPETITION.
*/
int RepTree::GetNodeType()const{
return this->type;
}
/*
~NumberOfSons~
This functions returns the number of sons of this node.
*/
int RepTree::NumberOfSons()const{
if(type==SIMPLE) return 0;
if(type==REPETITION) return 1;
return content;
}
/*
~NumberofNodesWithType~
This function computes the number of nodes with the given type.
*/
int RepTree::NumberOfNodesWithType(int type)const{
if(this->type==SIMPLE){
if(this->type==type)
return 1;
else
return 0;
}
int res = 0;
if(this->type==COMPOSITION)
for(int i=0;i<content;i++)
res += (sons[i])->NumberOfNodesWithType(type);
if(this->type==REPETITION)
res = sons[0]->NumberOfNodesWithType(type);
if(this->type==type)
res++;
return res;
}
/*
~NumberOfCompositeSons~
This very spicialized function computes the number of sons of
all composite moves of this tree.
*/
int RepTree::NumberOfCompositeSons()const{
if(type==SIMPLE)
return 0;
if(type==REPETITION)
return sons[0]->NumberOfCompositeSons();
int res=content;
for(int i=0;i<content;i++)
res+= sons[i]->NumberOfCompositeSons();
return res;
}
/*
~RepCount~
This function returns the number of repetitions for a
node of type REPETITION. If this node id of another type,
the result will be -1.
*/
int RepTree::RepCount()const{
if(type!=REPETITION) return -1;
return content;
}
/*
~Content~
This function can be used to receive the constent of a simple
node. If the node is not of thios type, the result will be
-1.
*/
int RepTree::Content()const{
if(type!=SIMPLE) return -1;
return content;
}
/*
~DetectRepetitions~
This is the most importatant function of this class. Starting with
an composite tree, this function detects repetitions in the sons and
replaces it by the appropriate nodes.
The basic idea of this algorithms is to detect repetitions of growing
length. First, all repetitions of the current lengths are detected.
If no repetition is found, we continue with the incremented length.
We check wether equal repetitions are found. Each of this gets the
same id. This makes it possible to detect nested repetitions. We
replace the sequels recognized as repetition by the appropriate
repetition-trees and start a new search with length 1.
*/
void RepTree::DetectRepetitions(){
// only for composite nodes, this makes sense
if(this->type!=COMPOSITION)
return;
// we search for repetitions of currentlength
int currentlength = 1;
// this is the current position in the sons array
int currentpos;
/*
To detect a repetition of the currentlength, we
need at least 2*currentlength elements
*/
while(currentlength <= content /2){ // check different lengths
currentpos = 0;
// list for storing the repetition found
List<replacement>* RepList= new List<replacement>();
Iterator<replacement>* It = new Iterator<replacement>(RepList);
int noReplacements = 0; // number of replacements
int noElements = 0; // number of involved sons
while(currentpos <= content-2*currentlength){
/*
compute the number of potential repetitions
This meanas, that we only check for cycles of this length without
checking the inner parts of this cycles.
*/
int posrepcount=-1;
bool stop =false;
for(int i=currentpos+currentlength;
i<=content&&!stop;
i=i+currentlength){
if(i==content)
posrepcount++;
else{
if(GetSon(currentpos)->EqualID(GetSon(i)))
posrepcount++;
else{
if(i<content)
posrepcount++;
stop=true;
}
}
}
/*
At this point wen know that starting from currentpos, posrepcount
cycles of length currentlength exist. Now we check the inner parts
of this cycles and count the actual repetitions.
*/
int repcount=0;
bool repfound = true;
for(int rep=0;rep<posrepcount&&repfound;rep++){
for(int i=1;i<currentlength&&repfound;i++){
int firstpos = currentpos+i;
int secondpos = currentpos+(1+repcount)*currentlength+i;
if(secondpos==content){
repfound = true;
} else{
RepTree* son1 = GetSon(firstpos);
RepTree* son2 = GetSon(secondpos);
repfound = son1->EqualID(son2);
}
}
if(repfound)
repcount++;
}
if(repcount==0){
// if no repetition is found starting from the current position,
// we start a new search from the next position
currentpos++;
}else{
/*
From the current position , we have found repcount repetitions.
We create a replacement for it and store it in a list.
*/
replacement* r = new replacement();
r->startindex=currentpos;
r->endindex= currentpos+(repcount+1)*currentlength-1;
if(currentlength>1){
r->replacetree=new RepTree(sons,r->startindex,
r->startindex+currentlength-1,
repcount+1);
} else { // only one son is to repeat, no composition is needed
r->replacetree=new RepTree(sons[currentpos],repcount+1);
}
/*
Now we check wether this repetition exists already.
If it is so, the id of the new created repetition tree
will be taken from the existing one.
*/
It->Reset();
replacement r2;
bool found = false;
while(It->HasNext()&&!found){
r2 = It->Next();
if(r2.replacetree->EqualWithDepth(r->replacetree,2)){
r->replacetree->id = r2.replacetree->id;
if(r->replacetree->type==REPETITION)
r->replacetree->sons[0]->id = r2.replacetree->sons[0]->id;
found=true;
}
}
// we store the repetition in the list
RepList->Append(*r);
noReplacements++; // one replacement more
noElements=noElements + r->endindex - r->startindex+1;
// set the current position behind the repetition
currentpos = currentpos+(repcount+1)*currentlength;
}
}
/*
At this point, we have stored all repetitions found in the sons
stored in the list. If repetitions exists, we have to replace it
by a real repetition. If not, we look for repetitions with a greater
length.
*/
if(RepList->IsEmpty()){ // no repetition found
// start a new search with incremented length
delete RepList;
delete It;
currentlength++;
currentpos=0;
} else{
// now we replace the sons in fact
int newsize = content-noElements+noReplacements;
RepTree** newsons;
newsons = new RepTree*[newsize];
It->Reset();
// we know that It has a element because the list is not empty
replacement r=It->Next();
int index = 0; // the current index in the sons
int newindex=0;// the current index in the new sons
bool done=false;
while(index< content){
if(!done){
if(index!=r.startindex){ // copy the son
newsons[newindex]=sons[index];
index++;
newindex++;
}else{
newsons[newindex]=r.replacetree;
newindex++;
index = index+r.endindex-r.startindex+1;
if(It->HasNext())
r=It->Next();
else
done=true;
}
}else{ // no more repetitions
newsons[newindex]=sons[index];
index++;
newindex++;
}
}
if(newindex!=newsize){
std::cerr << "newindex = " << newindex <<
" != " << newsize << " = newsize \n";
exit(-1);
}
delete[] sons; // deallocate the old sons
sons = newsons; // assign the sons the the new computed ones
content=newsize;
delete RepList;
delete It;
currentlength=1;
currentpos=0;
}
}
/* PostProcessing:
If this composite move has only a single son, we replace this node
by its son.This my be the case if initial only a single son has
exist or the sonlist is converted to a single repetition
*/
if(content==1){ // a single son is not allowed in a composition
RepTree* son = sons[0];
type = son->type;
content = son->content;
id = son->id;
if(type==COMPOSITION){
sons= new RepTree*[content];
for(int i=0;i<content;i++)
sons[i] = son->sons[i];
}else if(type==SIMPLE){
sons=0;
}else {
sons = new RepTree*[1];
sons[0] = son->sons[0];
}
delete son;
}
}
/*
~Print~
This function prints out the tree in a textual form. The depth is used
for printing the correct indent.
*/
void RepTree::Print(int depth){
std::string indent = " ";
if(this->type==SIMPLE){
//print ident
for(int i=0;i<2*depth;i++)
std::cout << indent;
std::cout << content << std::endl;
} else if (this->type==COMPOSITION){
int mid = content /2;
for(int i=0;i<mid;i++)
sons[i]->Print(depth+1);
for(int i=0;i<2*depth;i++)
std::cout << indent;
std::cout << "C[" << content << "]\n";
for(int i=mid;i<content;i++)
sons[i]->Print(depth+1);
} else if(this->type==REPETITION) {
for(int i=0;i<2*depth;i++)
std::cout << indent;
std::cout << "R[" << content << "]" << std::endl;
sons[0]->Print(depth+1);
} else{
std::cout << "unknown nodetype " << std::endl;
}
}
/*
~Print~
This function prints out the tree in a textual form.
*/
void RepTree::Print(){
Print(0);
}
/*
~PrintNlValue~
This function prints out the value of the nested list representation
of this tree.
*/
void RepTree::PrintNlValue(){
if(type==SIMPLE){
std::cout << " " << content << " " ;
}
if(type==REPETITION){
std::cout << "(";
std::cout << "\"R[" << content << "]\" (";
sons[0]->PrintNlValue();
std::cout << "))\n";
}
if(type==COMPOSITION){
std::cout << "(";
std::cout << "\"C\"( ";
for(int i=0;i<content;i++){
sons[i]->PrintNlValue();
std::cout << " ";
}
std::cout <<"))\n";
}
}
/*
~PrintNL~
This function prints out this tree in nested list format
inclusive type information.
*/
void RepTree::PrintNL(){
std::cout << " ( tree ";
PrintNlValue();
std::cout << ")";
}
} // namespace periodic