moab
element_tree.hpp
Go to the documentation of this file.
00001 
00011 #include <vector>
00012 #include <set>
00013 #include <iostream>
00014 #include <map>
00015 #include <algorithm>
00016 #include <bitset>
00017 #include <numeric>
00018 #include <cmath>
00019 #include <tr1/unordered_map>
00020 #include <limits>
00021 
00022 #include "common_tree.hpp"
00023 
00024 #ifndef ELEMENT_TREE_HPP
00025 #define ELEMENT_TREE_HPP
00026 namespace moab {
00027 //forward declarations
00028 
00029 template< typename _Entity_handles, 
00030       typename _Box, 
00031       typename _Moab,
00032       typename _Parametrizer> class Element_tree;
00033 
00034 //non-exported functionality
00035 namespace  {
00036 namespace _element_tree { 
00037 template< typename Iterator>
00038 struct Iterator_comparator{
00039 typedef typename Iterator::value_type Value;
00040 bool operator()(const Value & a, const Value & b){
00041     return a->second.second.to_ulong() < b->second.second.to_ulong();
00042 }
00043 }; //Iterator_comparator
00044 
00045 template< typename Data>
00046 struct Split_comparator {
00047   //we minimizes ||left| - |right|| + |middle|^2 
00048   double split_objective( const Data & a) const {
00049     if (a.second.sizes[ 2]==0 || a.second.sizes[ 0] == 0){
00050         return std::numeric_limits< std::size_t>::max();
00051     }
00052     const double total = a.second.sizes[ 0]+a.second.sizes[ 2];
00053     const int max = 2*(a.second.sizes[ 2]>a.second.sizes[ 0]);
00054     
00055     return (a.second.sizes[ max] -a.second.sizes[ 2*(1-(max==2))])/total;
00056   }
00057   bool operator()( const Data & a, const Data & b) const {
00058     return split_objective( a) < split_objective( b);
00059   }
00060 }; //Split_comparator
00061 
00062 template< typename Partition_data, typename Box>
00063 void correct_bounding_box( const Partition_data & data, Box & box, 
00064                const int child){
00065     const int dim = data.dim;
00066     switch( child){
00067         case 0:
00068             box.max[ dim] = data.left_rightline;
00069             break;
00070         case 1:
00071             box.max[ dim] = data.right_line;
00072             box.min[ dim] = data.left_line;
00073             break;
00074         case 2:
00075             box.min[ dim] = data.right_leftline;
00076             break;
00077     }
00078     #ifdef ELEMENT_TREE_DEBUG
00079     print_vector( data.bounding_box.max);
00080     print_vector( data.bounding_box.min);
00081     print_vector( box.max);
00082     print_vector( box.min);
00083     #endif
00084 }
00085 
00086 template< typename Box>
00087 struct _Partition_data{
00088     typedef _Partition_data< Box> Self;
00089     //default constructor
00090     _Partition_data():sizes(3,0),dim(0){}
00091     _Partition_data( const Self & f){ *this=f; }
00092     _Partition_data( const Box & _box, int _dim): sizes(3,0),
00093     bounding_box( _box), split((_box.max[ _dim] + _box.min[ _dim])/2.0), 
00094     left_line( split), right_line( split), dim( _dim){}
00095     _Partition_data& operator=( const Self & f){
00096         sizes = f.sizes;
00097         bounding_box = f.bounding_box;
00098         split = f.split;
00099         left_line = f.left_line;
00100         right_line = f.right_line;
00101         right_leftline=f.right_leftline;
00102         left_rightline=f.left_rightline;
00103         dim = f.dim;
00104         return *this;
00105     }
00106     std::vector< std::size_t> sizes;
00107     Box bounding_box;
00108     double split;
00109     double left_line;
00110     double right_line;
00111     double right_leftline;
00112     double left_rightline;
00113     int dim;
00114     std::size_t left()  const { return sizes[ 0]; }
00115     std::size_t middle()const { return sizes[ 1]; }
00116     std::size_t right() const { return sizes[ 2]; }
00117 }; // Partition_data
00118 
00119 template< typename _Entity_handles, typename _Entities>
00120 class _Node{
00121     //public types:
00122     public:
00123     typedef _Entity_handles Entity_handles;
00124     typedef _Entities Entities;
00125 
00126     //private types:
00127     private:
00128     typedef _Node< _Entity_handles, _Entities> Self;
00129 
00130     //Constructors
00131     public:
00132     //Default constructor
00133     _Node(): children(3,-1), 
00134     left_( children[ 0]), middle_( children[ 1]),
00135     right_( children[ 2]),
00136     dim( -1), split( 0),
00137          left_line( 0), right_line( 0),
00138         entities( 0) {}
00139 
00140     //Copy constructor
00141     _Node( const Self & from):
00142     children( from.children), 
00143     left_( children[ 0]), middle_( children[ 1]),
00144     right_( children[ 2]),
00145     dim( from.dim), split( from.split),
00146     left_line( from.left_line), right_line( from.right_line), 
00147     entities( from.entities) {}
00148 
00149     public:
00150     template< typename Iterator>
00151     void assign_entities(const Iterator & begin, const Iterator & end){
00152         entities.reserve( std::distance( begin, end)); 
00153         for( Iterator i = begin; i != end; ++i){
00154             entities.push_back( std::make_pair((*i)->second.first, 
00155                                 (*i)->first));
00156         }
00157     }
00158 
00159     // Functionality
00160     public: 
00161     bool leaf() const { return children[ 0] == -1 && 
00162                        children[ 1] == -1 && 
00163                        children[ 2] == -1; }
00164     Self& operator=( const Self & from){
00165         children=from.children;
00166         dim=from.dim;
00167         left_ = from.left_;
00168         middle_ = from.middle_;
00169         right_ = from.right_;
00170         split=from.split;
00171         left_line=from.left_line;
00172         right_line=from.right_line;
00173         entities=from.entities;
00174         return *this;
00175     }
00176     template< typename Box>
00177     Self& operator=( const _Partition_data< Box> & from){
00178         dim=from.dim;
00179         split=from.split;
00180         left_line=from.left_line;
00181         right_line=from.right_line;
00182         return *this;
00183     }
00184     //private data members:
00185     private:
00186     //indices of children
00187     std::vector< int> children;
00188     int & left_, middle_, right_;
00189     int dim; //split dimension
00190     double split; //split position
00191     double left_line;
00192     double right_line;
00193     Entities entities;
00194 
00195     //Element_tree can touch my privates.
00196     template< Entity_handles, typename B> friend class moab::Element_tree;
00197 }; //class Node
00198 
00199 } //namespace _element_tree
00200 } // anon namespace 
00201 
00202 template< typename _Entity_handles,
00203       typename _Box,
00204       typename _Moab, 
00205       typename _Parametrizer>
00206 class Element_tree {
00207 
00208 //public types
00209 public:
00210     typedef  _Entity_handles Entity_handles;
00211     typedef  _Box Box;
00212     typedef  _Moab Moab;
00213     typedef _Parametrizer Parametrizer;
00214     typedef typename Entity_handles::value_type Entity_handle;
00215     
00216 //private types
00217 private: 
00218     typedef Element_tree< _Entity_handles, 
00219                   _Box, 
00220                   _Moab, 
00221                   _Parametrizer> Self; 
00222     typedef std::pair< Box, Entity_handle>  Leaf_element;
00223     typedef _element_tree::_Node< Entity_handles, std::vector< Leaf_element> > Node;
00224     //int is because we only need to store  
00225     #define MAX_ITERATIONS 2
00226     typedef  common_tree::_Element_data< Box, std::bitset<NUM_DIM*MAX_ITERATIONS*2> > 
00227                                 Element_data;
00228     typedef std::vector< Node> Nodes;
00229     //TODO: we really want an unordered map here, make sure this is kosher..
00230     typedef std::tr1::unordered_map< Entity_handle, Element_data> 
00231                                 Element_map;
00232     typedef typename std::vector< typename Element_map::iterator> 
00233                                 Element_list;
00234     typedef _element_tree::_Partition_data< Box> Partition_data;
00235 //public methods
00236 public:
00237 //Constructor
00238 Element_tree( Entity_handles & _entities, Moab & _moab, Box & _bounding_box, 
00239           Parametrizer & _entity_contains): 
00240     entity_handles_( _entities), tree_(), moab( _moab), 
00241     bounding_box( _bounding_box), entity_contains( _entity_contains){
00242     tree_.reserve( _entities.size());
00243     Element_map element_map( _entities.size());
00244     Partition_data _data;
00245     common_tree::construct_element_map( entity_handles_, element_map, 
00246                         _data.bounding_box, moab);
00247     bounding_box = _data.bounding_box;
00248     _bounding_box = bounding_box;
00249     Element_list element_ordering( element_map.size());
00250     std::size_t index = 0;
00251     for(typename Element_map::iterator i = element_map.begin(); 
00252                       i != element_map.end(); ++i, ++index){
00253         element_ordering[ index] = i;
00254     }
00255     //We only build nonempty trees
00256     if( element_ordering.size()){ 
00257         //initially all bits are set
00258         std::bitset< 3> directions( 7);
00259         tree_.push_back( Node());
00260         int depth = 0;
00261         build_tree( element_ordering.begin(), 
00262                 element_ordering.end(),
00263                 0, directions, _data, depth);
00264         std::cout << "depth: " << depth << std::endl; 
00265     }
00266 }
00267 
00268 //Copy constructor
00269 Element_tree( Self & s): entity_handles_( s.entity_handles_), 
00270              tree_( s.tree_), moab( s.moab), 
00271              bounding_box( s.bounding_box){}
00272 
00273 //private functionality
00274 private:
00275 
00276 template< typename Iterator, typename Split_data>
00277 void compute_split( Iterator & begin, Iterator & end, 
00278              Split_data & split_data, bool iteration=false){
00279     typedef typename Iterator::value_type::value_type Map_value_type;
00280     typedef typename Map_value_type::second_type::second_type Bitset;
00281     //we will update the left/right line
00282     double & left_line = split_data.left_line;
00283     double & right_line = split_data.right_line;
00284     double & split = split_data.split;
00285     const int & dim = split_data.dim;
00286     #ifdef ELEMENT_TREE_DEBUG
00287     std::cout << std::endl; 
00288     std::cout << "-------------------" << std::endl; 
00289     std::cout << "dim: " << dim << " split: " << split << std::endl;
00290     std::cout << "bounding_box min: "; 
00291     print_vector( split_data.bounding_box.min); 
00292     std::cout << "bounding_box max: "; 
00293     print_vector( split_data.bounding_box.max);
00294     #endif
00295     //for each elt determine if left/middle/right
00296     for(Iterator i = begin; i != end; ++i){
00297         const Box & box =  (*i)->second.first;
00298         Bitset & bits =  (*i)->second.second;
00299         //will be 0 if on left, will be 1 if in the middle
00300         //and 2 if on the right;
00301         const bool on_left = (box.max[ dim] < split);
00302         const bool on_right = (box.min[ dim] > split);
00303         const bool in_middle = !on_left && !on_right;
00304         //set the corresponding bits in the bit vector
00305         // looks like: [x_1 = 00 | x_2 = 00 | .. | z_1 = 00 | z_2 = 00]
00306         // two bits, left = 00, middle = 01, right = 10
00307         const int index = 4*dim + 2*iteration;
00308         if( on_left){ split_data.sizes[ 0]++; }
00309         else if(in_middle){
00310             split_data.sizes[ 1]++;
00311             bits.set( index, 1);
00312             left_line  = std::min( left_line,  box.min[ dim]);
00313             right_line = std::max( right_line, box.max[ dim]);
00314         }else if( on_right){
00315             bits.set( index+1, 1);
00316             split_data.sizes[ 2]++;
00317         }
00318     }
00319     #ifdef ELEMENT_TREE_DEBUG
00320     std::size_t _count = std::accumulate( split_data.sizes.begin(), 
00321                           split_data.sizes.end(), 0);
00322     std::size_t total = std::distance( begin, end);
00323     if( total != _count ){
00324         std::cout << total << "vs. " <<  _count << std::endl;
00325 
00326     }
00327     std::cout <<  " left_line: " << left_line;
00328     std::cout <<  " right_line: " << right_line << std::endl;
00329     std::cout << "co/mputed partition size: ";
00330     print_vector( split_data.sizes);
00331     std::cout << "-------------------" << std::endl; 
00332     #endif
00333 }
00334 
00335 template< typename Split_data>
00336 bool update_split_line( Split_data & data) const{
00337     const int max = 2*(data.sizes[ 2]>data.sizes[ 0]);
00338     const int min = 2*(1-(max==2));
00339     bool one_side_empty = data.sizes[ max]==0 || data.sizes[ min]==0;
00340     double balance_ratio = data.sizes[ max] - data.sizes[ min];
00341     //if ( !one_side_empty && balance_ratio < .05*total){ return false; }
00342     if( !one_side_empty){
00343         //if we have some imbalance on left/right 
00344         //try to fix the situation 
00345         balance_ratio /= data.sizes[ max];
00346         data.split += (max-1)*balance_ratio*(data.split/2.0);
00347     }else{
00348         //if the (left) side is empty move the split line just past the 
00349         //extent of the (left) line of the middle box.
00350         //if middle encompasses everything then wiggle 
00351         //the split line a bit and hope for the best..
00352         const double left_distance = 
00353                     std::abs(data.left_line-data.split);    
00354             const double right_distance = 
00355                     std::abs(data.right_line-data.split);
00356         if( (data.sizes[ 0] == 0) && (data.sizes[ 2] != 0)){
00357             data.split += right_distance;
00358         }else if (data.sizes[ 2]==0 && data.sizes[ 0] != 0){
00359             data.split -= left_distance;
00360         }else{
00361             data.split *=1.05;
00362         }
00363     }
00364     data.left_line = data.right_line = data.split;
00365     data.sizes.assign( data.sizes.size(), 0);
00366     return true;
00367 }
00368 
00369 template< typename Iterator, 
00370       typename Split_data, 
00371       typename Directions>
00372 void determine_split( Iterator & begin, 
00373               Iterator & end, 
00374               Split_data & data, 
00375               const Directions & directions){ 
00376     typedef typename Iterator::value_type Pair;
00377     typedef typename Pair::value_type Map_value_type;
00378     typedef typename Map_value_type::second_type::second_type Bitset;
00379     typedef typename Map_value_type::second_type::first_type Box;
00380     typedef typename std::map< std::size_t, Split_data> Splits;
00381     typedef typename Splits::value_type Split;  
00382     typedef _element_tree::Split_comparator< Split> Comparator;
00383     Splits splits;
00384     for (std::size_t dir = 0; dir < directions.size(); ++dir){
00385         if( directions.test( dir)){
00386             Split_data split_data( data.bounding_box, dir);
00387             compute_split( begin, end, split_data);
00388             splits.insert( std::make_pair(2*dir, split_data));
00389             if( update_split_line( split_data)){
00390                 compute_split( begin, end, split_data, true);
00391                 splits.insert( std::make_pair( 2*dir+1,
00392                                    split_data) );
00393             }
00394         }
00395     }
00396     Split best = *std::min_element( splits.begin(), splits.end(), 
00397                     Comparator());
00398     #ifdef ELEMENT_TREE_DEBUG
00399     std::cout << "best: " << Comparator().split_objective( best) << " ";
00400     print_vector( best.second.sizes);
00401     #endif 
00402     const int dir = best.first/2;
00403     const int iter = best.first%2;
00404     double & left_rightline = best.second.left_rightline= 
00405                         best.second.bounding_box.min[ dir];
00406     double & right_leftline = best.second.right_leftline = 
00407                     best.second.bounding_box.max[ dir];
00408     Bitset mask( 0);
00409     mask.flip( 4*dir+2*iter).flip( 4*dir+2*iter+1);
00410     for(Iterator i = begin; i != end; ++i){
00411         Bitset & bits = (*i)->second.second;
00412         const Box & box =  (*i)->second.first;
00413         //replace 12 bits with just two.
00414         bits &= mask;
00415         bits >>= 4*dir+2*iter;
00416         //if box is labeled left/right but properly contained 
00417         //in the middle, move the element into the middle.
00418         //we can shrink the size of left/right
00419         switch( bits.to_ulong()){
00420             case 0:
00421                 if ( box.max[ dir] > best.second.left_line){ 
00422                     left_rightline = std::max( 
00423                         left_rightline, box.max[ dir]);
00424                 }
00425                 break;
00426             case 2:
00427                 if ( box.min[ dir] < best.second.right_line){ 
00428                     right_leftline = std::min( 
00429                         right_leftline, box.max[ dir]);
00430                 }
00431                 break;
00432         }
00433     }
00434     data = best.second;
00435 }
00436 
00437 //define here for now.
00438 #define ELEMENTS_PER_LEAF 30
00439 #define MAX_DEPTH 30
00440 #define EPSILON 1e-1
00441 template< typename Iterator, typename Node_index, 
00442       typename Directions, typename Partition_data>
00443 void build_tree( Iterator begin, Iterator end, 
00444          const Node_index node, 
00445          const Directions & directions, 
00446          Partition_data & _data,
00447          int & depth, 
00448          const bool is_middle = false){
00449     std::size_t number_elements = std::distance(begin, end);
00450     if ( depth < MAX_DEPTH && 
00451         number_elements > ELEMENTS_PER_LEAF && 
00452         (!is_middle || directions.any())){
00453         determine_split( begin, end,  _data, directions);
00454         //count_sort( begin, end, _data);
00455         std::sort( begin, end,
00456              _element_tree::Iterator_comparator< Iterator>());
00457         //update the tree
00458         tree_[ node] = _data;
00459         Iterator middle_begin( begin+_data.left());
00460         Iterator middle_end( middle_begin+_data.middle());
00461         std::vector< int> depths(3, depth);
00462         //left subtree
00463         if( _data.left()>0){
00464             Partition_data data( _data);
00465             tree_.push_back( Node());
00466             tree_[ node].children[ 0] = tree_.size()-1;
00467             correct_bounding_box( _data, data.bounding_box, 0);
00468             Directions new_directions( directions);
00469             const bool axis_is_very_small = 
00470              (data.bounding_box.max[ _data.dim] - 
00471                 data.bounding_box.min[ _data.dim] < EPSILON);
00472             new_directions.set( _data.dim, axis_is_very_small); 
00473             build_tree( begin, middle_begin, 
00474                     tree_[ node].children[ 0], 
00475                     new_directions, data, ++depths[ 0],
00476                     is_middle);
00477         }
00478         //middle subtree
00479         if( _data.middle()>0){
00480             Partition_data data( _data);
00481             tree_.push_back( Node());
00482             tree_[ node].children[ 1] = tree_.size()-1;
00483             correct_bounding_box( _data, data.bounding_box, 1);
00484             //force the middle subtree to split
00485             //in a different direction from this one
00486             Directions new_directions( directions);
00487             new_directions.flip( tree_[node].dim);
00488             bool axis_is_very_small = 
00489              (data.bounding_box.max[ _data.dim] - 
00490                 data.bounding_box.min[ _data.dim] < EPSILON);
00491             new_directions.set( _data.dim, axis_is_very_small); 
00492             build_tree( middle_begin, middle_end,
00493                     tree_[ node].children[ 1], 
00494                     new_directions, data, 
00495                     ++depths[ 1], true);
00496         }
00497         //right subtree
00498         if( _data.right()>0){
00499             Partition_data data( _data);
00500             tree_.push_back( Node());
00501             tree_[ node].children[ 2] = tree_.size()-1;
00502             correct_bounding_box( _data, data.bounding_box, 2);
00503             Directions new_directions( directions);
00504             const bool axis_is_very_small = 
00505              (data.bounding_box.max[ _data.dim] - 
00506                 data.bounding_box.min[ _data.dim] < EPSILON);
00507             new_directions.set( _data.dim, axis_is_very_small); 
00508 
00509             build_tree( middle_end, end, tree_[ node].children[ 2],
00510                     directions, data, ++depths[ 2], is_middle);
00511         }
00512         depth = *std::max_element(depths.begin(), depths.end());
00513     }
00514     if( tree_[ node].leaf()){
00515         common_tree::assign_entities(tree_[ node].entities, begin, end);
00516     }
00517 }
00518 
00519 template< typename Vector, typename Node_index, typename Result>
00520 Result& _find_point( const Vector & point, 
00521                  const Node_index & index,
00522              Result & result) const{
00523     typedef typename Node::Entities::const_iterator Entity_iterator;
00524     typedef typename std::pair< bool, Vector> Return_type;
00525     const Node & node = tree_[ index];
00526     if( node.leaf()){
00527         //check each node
00528         for( Entity_iterator i = node.entities.begin(); 
00529                      i != node.entities.end(); ++i){
00530             if( common_tree::box_contains_point( i->first, point)){
00531                 Return_type r = entity_contains( moab, 
00532                                      i->second, 
00533                                  point);
00534                 if( r.first){ result = 
00535                     std::make_pair( i->second, r.second);
00536                 }
00537                 return result;
00538             }
00539         }
00540         return Result(0, point);
00541     }
00542     if( point[ node.dim] < node.left_line){
00543         return _find_point( point, node.left_, result);
00544     }else if( point[ node.dim] > node.right_line){
00545         return _find_point( point, node.right_, result);
00546     } else {
00547         Entity_handle middle =  _find_point( point, 
00548                             node.middle_, result);
00549         if( middle != 0){ return result; }
00550         if( point[ node.dim] < node.split){ 
00551             return _find_point( point, node.left_, result); 
00552         }
00553         return  _find_point( point, node.right_, result);
00554     }
00555 }
00556 
00557 //public functionality
00558 public:
00559 template< typename Vector, typename Result>
00560 Result& find( const Vector & point, Result & result) const{
00561     typedef typename Vector::const_iterator Point_iterator;
00562     typedef typename Box::Pair Pair; 
00563     typedef typename Pair::first_type Box_iterator;
00564     return  _find_point( point, 0, result);
00565 }
00566     
00567 
00568 //public accessor methods
00569 public:
00570 
00571 //private data members  
00572 private:
00573     const Entity_handles & entity_handles_;
00574     Nodes tree_;
00575     Moab & moab;
00576     Box bounding_box;
00577     Parametrizer entity_contains;
00578 
00579 }; //class Element_tree
00580 
00581 } // namespace moab
00582 
00583 #endif //ELEMENT_TREE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines