SparseLibrary  Version 1.6.0
BlockOrderer.hpp
1 /*
2  * Copyright (c) 2007-2014, A. N. Yzelman, Utrecht University 2007-2011;
3  * KU Leuven 2011-2014.
4  * R. H. Bisseling, Utrecht University 2007-2014.
5  *
6  * This file is part of the Sparse Library.
7  *
8  * This library was developed under supervision of Prof. dr. Rob H. Bisseling at
9  * Utrecht University, from 2007 until 2011. From 2011-2014, development continued
10  * at KU Leuven, where Prof. dr. Dirk Roose contributed significantly to the ideas
11  * behind the newer parts of the library code.
12  *
13  * The Sparse Library is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by the
15  * Free Software Foundation, either version 3 of the License, or (at your
16  * option) any later version.
17  *
18  * The Sparse Library is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with the Sparse Library. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 
28 /*
29  * File created by:
30  * A. N. Yzelman, Dept. of Mathematics, Utrecht University, 2010.
31  */
32 
33 
34 #ifndef _H_BLOCKORDERER
35 #define _H_BLOCKORDERER
36 
37 #include "SBDTree.hpp"
38 #include "Triplet.hpp"
39 #include <vector>
40 #include <map>
41 
42 #define NORMAL_DS 2 //ICRS
43 #define HORIZONTAL_DS -2 //ICCS
44 #define VERTICAL_DS 2 //ICRS
45 
47 template< typename T >
48 class BlockOrderer {
49 
50  protected:
51 
54 
56  std::vector< char > leftpass;
57 
59  std::vector< char > rightpass;
60 
62  void prefix( const unsigned long int index ) {
63  switch( traverse_mode ) {
64  case TRAVERSE_HEIGHT:
65  ++cur_height;
66  break;
67  case READOUT:
68  pre_readout( index );
69  break;
70  default:
71  std::cerr << "BlockOrderer:: Unknown or unset traverse mode!" << std::endl;
72  exit( EXIT_FAILURE );
73  }
74  }
75 
77  void infix( const unsigned long int index ) {
78  switch( traverse_mode ) {
79  case TRAVERSE_HEIGHT:
80  height[ index ] = cur_height;
81  break;
82  case READOUT:
83  in_readout( index );
84  break;
85  default:
86  std::cerr << "BlockOrderer:: Unknown or unset traverse mode!" << std::endl;
87  exit( EXIT_FAILURE );
88  }
89  }
90 
92  void postfix( const unsigned long int index ) {
93  switch( traverse_mode ) {
94  case TRAVERSE_HEIGHT:
95  --cur_height;
96  break;
97  case READOUT:
98  post_readout( index );
99  break;
100  default:
101  std::cerr << "BlockOrderer:: Unknown or unset traverse mode!" << std::endl;
102  exit( EXIT_FAILURE );
103  }
104  }
105 
107  void traverse() {
108  leftpass. resize( tree->size() );
109  rightpass.resize( tree->size() );
110  for( unsigned long int i=0; i<tree->size(); i++ ) leftpass[i] = rightpass[i] = 0;
111 
112  const unsigned long int root = tree->getRoot();
113  unsigned long int cur = root;
114 
115  while( true ) { //traverse! :)
116  //if this is a leaf node, call all the functions and move up
117  if( tree->isLeaf( cur ) ) {
118  prefix ( cur );
119  infix ( cur );
120  postfix( cur );
121  if( cur == root ) {
122  return; //done
123  } else
124  cur = tree->up( cur ); //move up
125  } else {
126  //this is an internal node
127  //if not passed left yet
128  if( !leftpass[ cur ] ) {
129  prefix( cur ); //execute prefix function
130  leftpass[ cur ] = 1; //set left pass
131  cur = tree->left( cur ); //go to left subtree
132  } else {
133  //if not passed right yet
134  if( !rightpass[ cur ] ) {
135  infix( cur ); //execute infix function
136  rightpass[ cur ] = 1; //set right pass
137  cur = tree->right( cur ); //go to right subtree
138  } else {
139  //passed children
140  postfix( cur ); //execute post function
141  if( cur == root ) {
142  return; //done
143  } else
144  cur = tree->up( cur ); //move up
145  }
146  }
147  }
148  }
149  std::cerr << "BlockOrderer::traverse: Reached what should be unreachable code!" << std::endl;
150  assert( false );
151  exit( EXIT_FAILURE );
152  }
153 
156 
157  // Helpers for determining node heights
158 
160  static const char TRAVERSE_HEIGHT = 0;
161 
163  unsigned long int *height;
164 
166  unsigned long int cur_height;
167 
169  void pre_height ( const unsigned long int index );
170 
172  void in_height ( const unsigned long int index );
173 
175  void post_height( const unsigned long int index );
176 
177  // Helpers for final tree read-out
178 
180  static const char READOUT = 1;
181 
182  // Following depends on exact block order
183 
185  virtual void pre_readout ( const unsigned long int index ) = 0;
186 
188  virtual void in_readout ( const unsigned long int index ) = 0;
189 
191  virtual void post_readout( const unsigned long int index ) = 0;
192 
194  std::vector< Triplet< T > > *items;
195 
197  std::vector< std::vector< Triplet< T > > > *output;
198 
200  std::vector< signed char > *datatype;
201 
203  inline bool left_horizontal( const unsigned long int index, const Triplet< T > triplet ) {
204  unsigned long int bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi, r_lo, r_hi, c_lo, c_hi;
205  this->tree->getSeparatorBB( index, bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi );
206  this->tree->rowBounds( index, r_lo, r_hi );
207  this->tree->columnBounds( index, c_lo, c_hi );
208  return ( triplet.i() >= r_lo && triplet.i() < r_hi && triplet.j() >= bb_c_lo && triplet.j() < c_lo );
209  }
210 
212  inline bool right_horizontal( const unsigned long int index, const Triplet< T > triplet ) {
213  unsigned long int bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi, r_lo, r_hi, c_lo, c_hi;
214  this->tree->getSeparatorBB( index, bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi );
215  this->tree->rowBounds( index, r_lo, r_hi );
216  this->tree->columnBounds( index, c_lo, c_hi );
217  return ( triplet.i() >= r_lo && triplet.i() < r_hi && triplet.j() >= c_hi && triplet.j() < bb_c_hi );
218  }
219 
221  inline bool upper_vertical( const unsigned long int index, const Triplet< T > triplet ) {
222  unsigned long int bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi, r_lo, r_hi, c_lo, c_hi;
223  this->tree->getSeparatorBB( index, bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi );
224  this->tree->rowBounds( index, r_lo, r_hi );
225  this->tree->columnBounds( index, c_lo, c_hi );
226  return ( triplet.i() >= bb_r_lo && triplet.i() < r_lo && triplet.j() >= c_lo && triplet.j() < c_hi );
227  }
228 
230  inline bool lower_vertical( const unsigned long int index, const Triplet< T > triplet ) {
231  unsigned long int bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi, r_lo, r_hi, c_lo, c_hi;
232  this->tree->getSeparatorBB( index, bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi );
233  this->tree->rowBounds( index, r_lo, r_hi );
234  this->tree->columnBounds( index, c_lo, c_hi );
235  return ( triplet.i() >= r_hi && triplet.i() < bb_r_hi && triplet.j() >= c_lo && triplet.j() < c_hi );
236  }
237 
239  inline bool middle( const unsigned long int index, const Triplet< T > triplet ) {
240  unsigned long int bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi, r_lo, r_hi, c_lo, c_hi;
241  this->tree->getSeparatorBB( index, bb_r_lo, bb_r_hi, bb_c_lo, bb_c_hi );
242  this->tree->rowBounds( index, r_lo, r_hi );
243  this->tree->columnBounds( index, c_lo, c_hi );
244  return ( triplet.i() >= r_lo && triplet.i() < r_hi && triplet.j() >= c_lo && triplet.j() < c_hi );
245  }
246  //Note: I'm perhaps expecting too much from the compiler; the inline keyword hopefully
247  // hints enough that these functions should really be integrated into the pre/in/post
248  // readout functions, outside the for loop along the nonzeroes...
249 
250  public:
251 
253  BlockOrderer(): tree( NULL ), height( NULL ), items( NULL ), output( NULL ), datatype( NULL ) {}
254 
256  virtual ~BlockOrderer() {
257  if( output != NULL ) {
258  std::cerr << "Warning: BlockOrderer::output was somehow not reset to NULL!" << std::endl;
259  }
260  }
261 
263  std::vector< std::vector< Triplet< T > > > induce( const std::vector< Triplet< T > > &input,
264  std::vector< unsigned long int > &r_hierarchy, std::vector< unsigned long int > &c_hierarchy,
265  std::vector< unsigned long int > &r_bounds, std::vector< unsigned long int > &c_bounds,
266  std::vector< signed char > *datatype ) {
267 
268  if( c_hierarchy.size() != r_hierarchy.size() ) {
269  std::cerr << "Error: Hierarchy vector is not of equal size!" << std::endl;
270  exit( EXIT_FAILURE );
271  }
272 
273  //Note:
274  //this function only passes around Triplet< T >'s, and does not have to do anything specific
275  //depending on T. Therefore, this function is templated, and not the entire class.
276  std::vector< std::vector< Triplet< T > > > ret;
277 
278 #ifdef _INFO
279  std::cout << "BlockOrderer, phase I (build tree)" << std::endl;
280 #endif
281  //phase running time: O( p log p )?
282 
283  tree = new SBDTree( r_hierarchy, c_hierarchy, r_bounds, c_bounds );
284 
285 #ifdef _INFO
286  std::cout << "BlockOrderer, phase II (build height map and dictionary)" << std::endl;
287 #endif
288  //phase running time: O( 2p-1 )
289 
290  //get height map
291  height = new unsigned long int[ tree->size() ];
292  for( unsigned long int i=0; i<tree->size(); ++i ) height[ i ] = ULONG_MAX;
293  std::map< unsigned long int, unsigned long int > row_translate, col_translate;
295  cur_height = 0;
296  traverse();
297  //check height map
298  for( unsigned long int i=0; i<tree->size(); ++i ) assert( height[ i ] != ULONG_MAX );
299 
300  //build dictionaries
301  unsigned long int lo, hi;
302  for( unsigned long int i=0; i<tree->size(); ++i ) {
303  tree->rowBounds( i, lo, hi );
304  //prevent translating indices to empty blocks
305  if( lo != hi )
306  row_translate[ hi ] = i;
307  tree->columnBounds( i, lo, hi );
308  if( lo != hi )
309  col_translate[ hi ] = i;
310  //TODO can anything meanful be inferred from empty blocks?
311  }
312 
313 #ifdef _INFO
314  std::cout << "BlockOrderer, phase III (assign triplets)" << std::endl;
315 #endif
316  //phase running time: O( nnz log p )
317 
318  items = new std::vector< Triplet< T > >[ tree->size() ];
319  std::vector< Triplet< double > >::const_iterator it = input.begin();
320  for( ; it != input.end(); ++it ) {
321  assert( row_translate.upper_bound( it->i() ) != row_translate.end() );
322  assert( col_translate.upper_bound( it->j() ) != col_translate.end() );
323  const unsigned long int i = row_translate.upper_bound( it->i() )->second;
324  const unsigned long int j = col_translate.upper_bound( it->j() )->second;
325  assert( i < tree->size() );
326  assert( j < tree->size() );
327  if( i == j )
328  items[ i ].push_back( *it );
329  else {
330  //not on a leaf node; on a separator cross (but which?)
331  //well, the one with the lowest height
332  assert( height[ i ] != height[ j ] );
333  if( height[ i ] < height [ j ] )
334  items[ i ].push_back( *it );
335  else
336  items[ j ].push_back( *it );
337  }
338  }
339 
340 #ifdef _INFO
341  std::cout << "BlockOrderer, phase IV (read out tree & return)" << std::endl;
342 #endif
343  //phase running time: O( 2p-1 )
344 
345  output = &ret;
346  this->datatype = datatype;
348  traverse();
349  output = NULL;
350  this->datatype = NULL;
351  unsigned int checksum = 0;
352  for( unsigned int i=0; i<ret.size(); i++ )
353  checksum += ret[ i ].size();
354  if( checksum != input.size() ) {
355  std::cerr << "Lost nonzeroes during readout (" << checksum << " while expecting " << input.size() << ")";
356  std::cerr << ", breaking off process..." << std::endl;
357  std::cerr << "(This is problably due to (too many) empty separators)" << std::endl;
358  exit( EXIT_FAILURE );
359  }
360 
361  //clean up
362  delete tree;
363  delete [] items;
364  delete [] height;
365 
366  //done
367  return ret;
368  }
369 };
370 
371 #endif
372 
Induces a block order by fully traversing an SBDTree.
Definition: BlockOrderer.hpp:48
void prefix(const unsigned long int index)
Prefix operation during SBD tree traversal.
Definition: BlockOrderer.hpp:62
void columnBounds(const unsigned long int index, unsigned long int &c_lo, unsigned long int &c_hi)
Returns the column bounds corresponding to a given node.
Definition: SBDTree.cpp:206
std::vector< std::vector< Triplet< T > > > induce(const std::vector< Triplet< T > > &input, std::vector< unsigned long int > &r_hierarchy, std::vector< unsigned long int > &c_hierarchy, std::vector< unsigned long int > &r_bounds, std::vector< unsigned long int > &c_bounds, std::vector< signed char > *datatype)
Induces this ordering on a set of nonzeroes.
Definition: BlockOrderer.hpp:263
virtual void post_readout(const unsigned long int index)=0
Postfix traversal code.
SBDTree * tree
The SBD tree to order the blocks of.
Definition: BlockOrderer.hpp:53
void post_height(const unsigned long int index)
Postfix code for height-determining traversal.
virtual void in_readout(const unsigned long int index)=0
Infix traversal code.
char isLeaf(const unsigned long int index)
Whether the given node is a leaf node.
Definition: SBDTree.cpp:214
ULI i() const
Definition: Triplet.hpp:70
void postfix(const unsigned long int index)
Postfix operation during SBD tree traversal.
Definition: BlockOrderer.hpp:92
unsigned long int cur_height
The current height at the traversal position.
Definition: BlockOrderer.hpp:166
bool left_horizontal(const unsigned long int index, const Triplet< T > triplet)
Helper function for determining place of a nonzero within a separator cross.
Definition: BlockOrderer.hpp:203
bool upper_vertical(const unsigned long int index, const Triplet< T > triplet)
Helper function for determining place of a nonzero within a separator cross.
Definition: BlockOrderer.hpp:221
unsigned long int left(const unsigned long int index)
Returns the left child of a given node.
Definition: SBDTree.cpp:180
std::vector< char > leftpass
Stores whether a node has been traversed from the left.
Definition: BlockOrderer.hpp:56
unsigned long int * height
Stores the height of a SBD node.
Definition: BlockOrderer.hpp:163
virtual ~BlockOrderer()
Base destructor.
Definition: BlockOrderer.hpp:256
void rowBounds(const unsigned long int index, unsigned long int &r_lo, unsigned long int &r_hi)
Returns the row bounds corresponding to a given node.
Definition: SBDTree.cpp:198
void in_height(const unsigned long int index)
Infix code for height-determining traversal.
bool right_horizontal(const unsigned long int index, const Triplet< T > triplet)
Helper function for determining place of a nonzero within a separator cross.
Definition: BlockOrderer.hpp:212
unsigned long int up(const unsigned long int index)
Returns the parent of a given node.
Definition: SBDTree.cpp:171
unsigned long int size()
Gets the number of nodes.
Definition: SBDTree.cpp:222
static const char READOUT
Mode flag for SBD tree readouts.
Definition: BlockOrderer.hpp:180
bool lower_vertical(const unsigned long int index, const Triplet< T > triplet)
Helper function for determining place of a nonzero within a separator cross.
Definition: BlockOrderer.hpp:230
virtual void pre_readout(const unsigned long int index)=0
Prefix traversal code.
void pre_height(const unsigned long int index)
Prefix code for height-determining traversal.
std::vector< std::vector< Triplet< T > > > * output
Output structure after SBD readout (series of blocks in the correct order).
Definition: BlockOrderer.hpp:197
unsigned long int right(const unsigned long int index)
Returns the right child of a given node.
Definition: SBDTree.cpp:189
unsigned long int getRoot()
Gets the root index.
Definition: SBDTree.cpp:226
static const char TRAVERSE_HEIGHT
Mode flag for height-determining traversal.
Definition: BlockOrderer.hpp:160
BlockOrderer()
Base constructor.
Definition: BlockOrderer.hpp:253
ULI j() const
Definition: Triplet.hpp:73
char traverse_mode
Sets the traversal mode.
Definition: BlockOrderer.hpp:155
std::vector< char > rightpass
Stores whether a node has been traversed from the right.
Definition: BlockOrderer.hpp:59
void infix(const unsigned long int index)
Infix operation during SBD tree traversal.
Definition: BlockOrderer.hpp:77
bool middle(const unsigned long int index, const Triplet< T > triplet)
Helper function for determining place of a nonzero within a separator cross.
Definition: BlockOrderer.hpp:239
std::vector< signed char > * datatype
The data type of each block.
Definition: BlockOrderer.hpp:200
Models a Separated Block Diagonal tree structure.
Definition: SBDTree.hpp:44
A single triplet value.
Definition: Triplet.hpp:52
void getSeparatorBB(const unsigned long int index, unsigned long int &r_lo, unsigned long int &r_hi, unsigned long int &c_lo, unsigned long int &c_hi)
Gets, from a separator node, the bounding box of the nonzeroes contained in the separator.
Definition: SBDTree.cpp:141
void traverse()
Traverses the SBD tree, makes call to prefix, infix, and postfix during traversal.
Definition: BlockOrderer.hpp:107
std::vector< Triplet< T > > * items
Nonzero storage at each node.
Definition: BlockOrderer.hpp:194