kopia lustrzana https://github.com/fellesverkstedet/fabmodules
244 wiersze
6.4 KiB
C++
244 wiersze
6.4 KiB
C++
#include <fstream>
|
|
|
|
#include "math_tree.hpp"
|
|
#include "node.hpp"
|
|
#include "switches.hpp"
|
|
|
|
using namespace std;
|
|
|
|
typedef boost::lock_guard<boost::mutex> locker;
|
|
|
|
MathTree::MathTree()
|
|
: root(NULL), levels(NULL), active_nodes(NULL), dNodes(NULL), parent(NULL)
|
|
{
|
|
// Nothing to do here
|
|
}
|
|
|
|
MathTree::~MathTree()
|
|
{
|
|
// If this tree is a clone, then notify the parent (because the parent will be
|
|
// waiting for this tree to be deleted before it can delete itself).
|
|
if (parent) {
|
|
locker lock(parent->mutex);
|
|
parent->done = true;
|
|
parent->condition.notify_one();
|
|
}
|
|
|
|
// Make sure that all children have been deleted.
|
|
wait_for_clones();
|
|
|
|
// Delete all nodes stored in the tree, from top to bottom (to prevent
|
|
// issues due to reference subtraction)
|
|
if (levels)
|
|
for (int i = num_levels - 1; i >= 0; --i) {
|
|
for (int j = 0; j < active_nodes[i]; ++j)
|
|
delete levels[i][j];
|
|
delete [] levels[i];
|
|
}
|
|
|
|
for (MathTreeIter it = constants.begin(); it != constants.end(); ++it)
|
|
delete *it;
|
|
|
|
delete [] levels;
|
|
delete [] active_nodes;
|
|
delete [] dNodes;
|
|
}
|
|
|
|
MathTree* MathTree::clone()
|
|
{
|
|
MathTree* m = new MathTree();
|
|
// cout << "MathTree::clone() is cloning " << this << " to " << m << endl;
|
|
m->num_levels = num_levels;
|
|
m->levels = new Node**[num_levels];
|
|
m->active_nodes = new int[num_levels];
|
|
m->dNodes = new list<int>[num_levels];
|
|
|
|
// Clone all of the active nodes.
|
|
// Since constants aren't changing, we don't need to clone them.
|
|
for (int i = 0; i < num_levels; ++i) {
|
|
m->active_nodes[i] = active_nodes[i];
|
|
m->levels[i] = new Node*[active_nodes[i]];
|
|
for (int j = 0; j < active_nodes[i]; ++j)
|
|
m->levels[i][j] = levels[i][j]->clone();
|
|
}
|
|
|
|
// If the entire tree is constant, then point back to this
|
|
// original tree's root.
|
|
if (num_levels)
|
|
m->root = m->levels[num_levels - 1][0];
|
|
else
|
|
m->root = root;
|
|
|
|
clones.push_back(new ThreadComm());
|
|
m->parent = clones.back();
|
|
|
|
return m;
|
|
}
|
|
|
|
void MathTree::wait_for_clones()
|
|
{
|
|
|
|
// Go through the list, waiting for each of the children.
|
|
list<ThreadComm*>::iterator it = clones.begin();
|
|
while (it != clones.end())
|
|
{
|
|
{
|
|
boost::unique_lock<boost::mutex> lock((**it).mutex);
|
|
while (!(**it).done)
|
|
(**it).condition.wait(lock);
|
|
}
|
|
delete *it;
|
|
it = clones.erase(it);
|
|
}
|
|
}
|
|
|
|
void MathTree::add(Node* n)
|
|
{
|
|
if (!n)
|
|
return;
|
|
else if (n->marked) {
|
|
constants.push_back(n);
|
|
} else {
|
|
unsigned int L = n->get_weight();
|
|
if (L + 1 > level_list.size())
|
|
level_list.resize(L + 1);
|
|
level_list[L].push_back(n);
|
|
}
|
|
}
|
|
|
|
// Converts the friendly, easy-to use C++ STL data structures into
|
|
// fast C-style arrays of pointers.
|
|
void MathTree::pack()
|
|
{
|
|
num_levels = level_list.size();
|
|
levels = new Node**[num_levels];
|
|
active_nodes = new int[num_levels];
|
|
dNodes = new list<int>[num_levels];
|
|
|
|
for (int i = 0; i < num_levels; ++i)
|
|
{
|
|
active_nodes[i] = level_list[i].size();
|
|
levels[i] = new Node*[active_nodes[i]];
|
|
int j = 0;
|
|
while (level_list[i].size()) {
|
|
levels[i][j++] = level_list[i].front();
|
|
level_list[i].pop_front();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MathTree::set_root(Node* r)
|
|
{
|
|
root = r;
|
|
}
|
|
|
|
int MathTree::node_count() const
|
|
{
|
|
int total = 0;
|
|
for(int i = 0; i < num_levels; ++i)
|
|
total += active_nodes[i];
|
|
return total;
|
|
}
|
|
|
|
int MathTree::constant_count() const
|
|
{
|
|
return constants.size();
|
|
}
|
|
|
|
|
|
// Evaluate a single point
|
|
void MathTree::eval(const float X,
|
|
const float Y,
|
|
const float Z)
|
|
{
|
|
for (int i = 0; i < num_levels; ++i)
|
|
for (int j = 0; j < active_nodes[i]; ++j)
|
|
levels[i][j]->eval(X, Y, Z);
|
|
}
|
|
|
|
// Evaluate an interval region
|
|
void MathTree::eval(const FabInterval& X,
|
|
const FabInterval& Y,
|
|
const FabInterval& Z)
|
|
{
|
|
for (int i = 0; i < num_levels; ++i)
|
|
for (int j = 0; j < active_nodes[i]; ++j)
|
|
levels[i][j]->eval(X, Y, Z);
|
|
}
|
|
|
|
void MathTree::push()
|
|
{
|
|
// Pass downwards through the tree. If a node is cached
|
|
// (meaning it won't change upon further recursion), then
|
|
// tell its children that they are no longer being watched.
|
|
|
|
// If all of a node's parents are no longer watching it, then
|
|
// remove that node from the tree as well (and inform its children)
|
|
|
|
// Keep track of how many nodes were removed from the tree
|
|
// in the dNodes[i] stack.
|
|
|
|
for (int i = num_levels - 2; i >= 0; --i) {
|
|
dNodes[i].push_back(0);
|
|
for (int j = 0; j < active_nodes[i]; ++j) {
|
|
if (levels[i][j]->cacheable())
|
|
{
|
|
levels[i][j]->deactivate();
|
|
swap(levels[i][j--], levels[i][--active_nodes[i]]);
|
|
dNodes[i].back()++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MathTree::pop()
|
|
{
|
|
// Increase the number of active nodes in the arrays so that
|
|
// previous cached nodes are now evaluated.
|
|
|
|
for (int i = 0; i < num_levels - 1; ++i) {
|
|
|
|
// Activate each of the previously disabled nodes.
|
|
for (int n = 0; n < dNodes[i].back(); ++n) {
|
|
levels[i][active_nodes[i]++]->activate();
|
|
}
|
|
dNodes[i].pop_back();
|
|
}
|
|
}
|
|
|
|
ostream& operator<<(ostream& o, const MathTree& t)
|
|
{
|
|
o << "Constants (" << t.constants.size() << " items)\n";
|
|
MathTreeConstIter it;
|
|
for (it = t.constants.begin(); it != t.constants.end(); ++it)
|
|
o << '\t' << **it << '\n';
|
|
o << endl;
|
|
|
|
for (int i = 0; i < t.num_levels; ++i)
|
|
{
|
|
o << "Level " << i << " (" << t.active_nodes[i] << " items)\n";
|
|
for (int j = 0; j < t.active_nodes[i]; ++j)
|
|
o << '\t' << *t.levels[i][j] << '\n';
|
|
o << endl;
|
|
}
|
|
return o;
|
|
}
|
|
|
|
void MathTree::export_dot(string filename) const
|
|
{
|
|
ofstream out;
|
|
out.open(filename.c_str());
|
|
out << "digraph math {\n"
|
|
<< "node [rank = min, fontsize = 14, fontname = Arial]\n";
|
|
MathTreeConstIter it;
|
|
for (it = constants.begin(); it != constants.end(); ++it)
|
|
(**it).dot(out);
|
|
|
|
for (int i = 0; i < num_levels; ++i)
|
|
for (int j = 0; j < active_nodes[i]; ++j)
|
|
levels[i][j]->dot(out);
|
|
|
|
out << "}\n";
|
|
out.close();
|
|
}
|