You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

469 lines
11 KiB

/*
* This file is part of the program ltl2dstar (http://www.ltl2dstar.de/).
* Copyright (C) 2005-2007 Joachim Klein <j.klein@ltl2dstar.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SAFRATREE_H
#define SAFRATREE_H
/** @file
* Provides class SafraTree.
*/
#include "common/BitSet.hpp"
#include "SafraTreeNode.hpp"
#include "RabinAcceptance.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
#include <memory>
#include <functional>
// forward declaration
template <class SafraTreeVisitor> class SafraTreeWalker;
/**
* A Safra tree, an ordered tree of SafraTreeNodes.
*/
class SafraTree {
public:
/**
* Constructor.
* @param N the maximum number of nodes.
*/
SafraTree(unsigned int N) {
if (N==0) {N=1;}
MAX_NODES=N;
_nodes=new SafraTreeNode*[MAX_NODES];
for (unsigned int i=0;i<MAX_NODES;i++) {
_nodes[i]=0;
}
// create root-node
newNode(0);
}
/** Copy constructor. */
SafraTree(const SafraTree& other) {
MAX_NODES=other.MAX_NODES;
_nodes=new SafraTreeNode*[MAX_NODES];
for (unsigned int i=0;i<MAX_NODES;i++) {
_nodes[i]=0;
if (other._nodes[i]!=0) {
_nodes[i]=newNode(i);
_nodes[i]->getLabeling()=other._nodes[i]->getLabeling();
_nodes[i]->setFinalFlag(other._nodes[i]->hasFinalFlag());
}
}
copySubTree(_nodes[0], other._nodes[0]);
}
/** Destructor. */
~SafraTree() {
for (unsigned int i=0;i<MAX_NODES;i++) {
delete _nodes[i];
}
delete[] _nodes;
}
/** Get the root node of the tree. */
SafraTreeNode* getRootNode() {return _nodes[0];}
/** Get the root node of the tree. */
const SafraTreeNode* getRootNode() const {return _nodes[0];}
/** Create a new node. The name is the next free node name. */
SafraTreeNode* newNode() {
for (unsigned int i=0;i<MAX_NODES;i++) {
if (_nodes[i]==0) {
return newNode(i);
}
}
return 0;
}
/** Create a new node with name <i>id</i>. */
SafraTreeNode* newNode(unsigned int id) {
assert(id<MAX_NODES);
assert(_nodes[id]==0);
_nodes[id]=new SafraTreeNode(id);
return _nodes[id];
}
/**
* Remove a SafraTreeNode from the tree,
* the node can have no children.
*/
void remove(SafraTreeNode *node) {
assert(_nodes[node->getID()]==node);
remove(node->getID());
}
/**
* Remove the SafraTreeNode <i>id</i> from the tree,
* the node can have no children.
*/
void remove(unsigned int id) {
assert(id<MAX_NODES);
_nodes[id]->removeFromTree();
delete _nodes[id];
_nodes[id]=0;
}
/**
* Remove all children of the SafraTreeNode <i>id</i>.
*/
void removeAllChildren(unsigned int id) {
assert(id<MAX_NODES);
SafraTreeNode *n=_nodes[id];
SafraTreeNode *child;
while ((child=n->getOldestChild())!=0) {
removeAllChildren(child->getID());
remove(child->getID());
}
}
/**
* Walk the tree post-order, calling the function
* void visit(SafraTree& tree, SafraTreeNode *node)
* in the SafraTreeVisitor on each node.
*/
template <class SafraTreeVisitor>
void walkTreePostOrder(SafraTreeVisitor& visitor) {
std::auto_ptr<SafraTreeWalker<SafraTreeVisitor> >
stw(new SafraTreeWalker<SafraTreeVisitor>(visitor));
stw->walkTreePostOrder(*this);
}
/**
* Walk the subtree rooted under node *top post-order,
* calling the function void visit(SafraTree& tree, SafraTreeNode *node)
* in the SafraTreeVisitor on each node.
*/
template <class SafraTreeVisitor>
void walkSubTreePostOrder(SafraTreeVisitor& visitor,
SafraTreeNode *top) {
std::auto_ptr<SafraTreeWalker<SafraTreeVisitor> >
stw(new SafraTreeWalker<SafraTreeVisitor>(visitor));
stw->walkSubTreePostOrder(*this, top);
}
/**
* Walk the subtree rooted under node *top (only the children, not *top itself)
* post-order, calling the function void visit(SafraTree& tree, SafraTreeNode *node)
* in the SafraTreeVisitor on each node.
*/
template <class SafraTreeVisitor>
void walkChildrenPostOrder(SafraTreeVisitor& visitor,
SafraTreeNode *top) {
std::auto_ptr<SafraTreeWalker<SafraTreeVisitor> >
stw(new SafraTreeWalker<SafraTreeVisitor>(visitor));
stw->walkSubTreePostOrder(*this,
top,
false // = don't visit top
);
}
/**
* Calculate the height of the tree.
*/
unsigned int treeHeight() {
if (getRootNode()!=0) {
return getRootNode()->treeHeight();
}
return 0;
}
/**
* Calculate the width of the tree.
*/
unsigned int treeWidth() {
if (getRootNode()!=0) {
return getRootNode()->treeWidth();
}
return 0;
}
/**
* Equality operator.
*/
bool operator==(const SafraTree& other) const{
if (other.MAX_NODES!=MAX_NODES) {return false;}
for (unsigned int i=0;i<MAX_NODES;i++) {
if (_nodes[i]==0) {
if (other._nodes[i]!=0) {
return false;
}
} else {
if (other._nodes[i]==0) {return false;}
if (!(*_nodes[i]==*other._nodes[i])) {
return false;
}
}
}
return true;
}
/**
* Checks equality when ignoring the node names.
*/
bool structural_equal_to(const SafraTree& other) const {
if (other.MAX_NODES!=MAX_NODES) {return false;}
const SafraTreeNode* this_root=this->getRootNode();
const SafraTreeNode* other_root=other.getRootNode();
if (this_root==0 || other_root==0) {
// return true if both are 0
return (this_root==other_root);
}
return this_root->structural_equal_to(*other_root);
}
/**
* Less-than operator when ignoring the node names.
*/
bool structural_less_than(const SafraTree& other) const {
if (other.MAX_NODES<MAX_NODES) {return true;}
const SafraTreeNode* this_root=this->getRootNode();
const SafraTreeNode* other_root=other.getRootNode();
if (this_root==0) {
if (other_root!=0) {
return true;
} else {
return false;
}
} else { // this_root !=0
if (other_root==0) {return false;}
return this_root->structural_less_than(*other_root);
}
}
/**
* Less-than operator
*/
bool operator<(const SafraTree& other) const{
if (MAX_NODES < other.MAX_NODES) {return true;}
for (unsigned int i=0;i<MAX_NODES;i++) {
if (_nodes[i]==0 && other._nodes[i]==0) {
;
} else if (_nodes[i]==0) {
return true;
} else if (other._nodes[i]==0) {
return false;
} else {
if (*_nodes[i]<*other._nodes[i]) {
return true;
} else if (*_nodes[i] == *other._nodes[i]) {
;
} else {
return false;
}
}
}
return false;
}
/** Get the maximum number of nodes. */
unsigned int getNodeMax() const {return MAX_NODES;}
/** Get SafraTreeNode with index <i>i</i>*/
SafraTreeNode* operator[](unsigned int i) {
return _nodes[i];
}
const SafraTreeNode* operator[](unsigned int i) const {
return _nodes[i];
}
/** Print the SafraTree on an output stream. */
friend std::ostream& operator<<(std::ostream& out,
SafraTree& st) {
if (st.getRootNode()==0) {
out << "<empty>" << std::endl;
} else {
st.printSubTree(out, 0, st.getRootNode());
}
return out;
}
/** Returns a string representation of the SafraTree */
std::string toString() {
std::ostringstream buf;
buf << *this;
return buf.str();
}
/** Returns a string representation in HTML of the SafraTree */
std::string toHTML() {
if (getRootNode()==0) {
return std::string("<TABLE><TR><TD>[empty]</TD></TR></TABLE>");
} else {
std::ostringstream buf;
getRootNode()->toHTML(buf);
return buf.str();
}
}
/**
* Calculate a hash value using HashFunction
* @param hashfunction the HashFunction
* @param only_structure ignore the nameing of the nodes
*/
template <class HashFunction>
void hashCode(HashFunction& hashfunction,
bool only_structure=false) {
SafraTreeNode* root=getRootNode();
if (root!=0) {
root->hashCode(hashfunction, only_structure);
}
}
/**
* Generate the appropriate acceptance signature for Rabin Acceptance for this tree
*/
void generateAcceptance(RabinAcceptance::AcceptanceForState acceptance) const {
for (unsigned int i=0;i<getNodeMax();i++) {
const SafraTreeNode *stn=(*this)[i];
if (stn==0) {
acceptance.addTo_U(i);
} else {
if (stn->hasFinalFlag()) {
acceptance.addTo_L(i);
}
}
}
}
void generateAcceptance(RabinAcceptance::RabinSignature& acceptance) const {
acceptance.setSize(getNodeMax());
for (unsigned int i=0;i<getNodeMax();i++) {
const SafraTreeNode *stn=(*this)[i];
if (stn==0) {
acceptance.setColor(i, RabinAcceptance::RABIN_RED);
} else {
if (stn->hasFinalFlag()) {
acceptance.setColor(i, RabinAcceptance::RABIN_GREEN);
} else {
acceptance.setColor(i, RabinAcceptance::RABIN_WHITE);
}
}
}
}
RabinAcceptance::RabinSignature generateAcceptance() const {
RabinAcceptance::RabinSignature s(getNodeMax());
generateAcceptance(s);
return s;
}
private:
/** The maximum number of nodex */
unsigned int MAX_NODES;
/** An array to store the nodes */
SafraTreeNode **_nodes;
/**
* Copy the subtree (the children) of *other
* to *top, becoming the children of *top
*/
void copySubTree(SafraTreeNode *top, SafraTreeNode *other) {
if (other==0) {return;}
for (SafraTreeNode::child_iterator it=other->children_begin();
it!=other->children_end();
++it) {
SafraTreeNode *n=_nodes[(*it)->getID()], *n_o=*it;
top->addAsYoungestChild(n);
copySubTree(n, n_o);
}
}
/**
* Print the subtree rooted at node *top to the output stream
* @param out the output stream
* @param prefix the number of spaces ' ' in front of each node
* @param top the current tree sub root
*/
void printSubTree(std::ostream& out,
unsigned int prefix,
SafraTreeNode* top) {
for (unsigned int i=0;i<prefix;i++) {
out << " ";
}
out << *top << std::endl;
for (SafraTreeNode::child_iterator it=top->children_begin();
it!=top->children_end();
++it) {
printSubTree(out, prefix+1, *it);
}
}
};
/** a std::shared_ptr for SafraTree */
typedef std::shared_ptr<SafraTree> SafraTree_ptr;
namespace std {
/** overload equal_to for SafraTree_ptr to compare the actual trees */
template <>
inline bool
std::equal_to<SafraTree_ptr>::operator()
(SafraTree_ptr const& x, SafraTree_ptr const& y) const {
return (*x)==(*y);
}
/** overload less for SafraTree_ptr to compare the actual trees */
template <>
inline bool
std::less<SafraTree_ptr>::operator()
(SafraTree_ptr const& x, SafraTree_ptr const& y) const {
return (*x)<(*y);
}
};
// include SafraTreeWalker after declaration, because it
// depends on SafraTree...
#include "SafraTreeWalker.hpp"
#endif