SparseLibrary  Version 1.6.0
HilbertArray.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 Computer Science, KU Leuven, 2012.
31  */
32 
33 
34 #ifndef _H_HILBERTARRAY
35 #define _H_HILBERTARRAY
36 
37 #include <vector>
38 #include <assert.h>
39 
40 #include "BigInt.hpp"
41 
48 template< typename T >
50 
51  protected:
52 
53  public:
54 
56  virtual void zax( const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end ) = 0;
57 
59  virtual void zxa( const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end ) = 0;
60 
62  virtual size_t bytesUsed() = 0;
63 
65  virtual ULI getFirstColumnIndex() = 0;
66 
68  virtual ULI getFirstRowIndex() = 0;
69 
71  virtual void moveToStart( const T *__restrict__ &x, T *__restrict__ &y, const T &v ) = 0;
72 
74  virtual void moveToNext( const T *__restrict__ &x, T *__restrict__ &y, const T &v ) = 0;
75 
78 
79 };
80 
89 template< typename T, typename I, typename hI, typename mI >
90 class HilbertArray : public HilbertArrayInterface< T > {
91 
92  protected:
93 
96 
98  I * array;
99 
101  I *__restrict__ curpos;
102 
105 
107  mI currow;
108 
110  mI curcol;
111 
113  size_t bytes;
114 
122  void decode( const hI coor, mI &row, mI &col ) {
123  //note: the decode must of course be in-tune with the encode
124  // operations in Matrix2HilbertCoordinates.cpp
125 
126  //max shift
127  const unsigned char maxshift = 2 * sizeof( mI ) > sizeof( hI ) ? 4 * sizeof( hI ) : 8 * sizeof( mI ) ;
128 
129  //since maxshift might be smaller than the #bits for a mI type, zero them out explicitly
130  row = col = 0;
131 
132 #ifdef _DEBUG
133  std::cout << "Decoding " << coor << "..." << std::endl;
134 #endif
135 
136  //set index mask
137  mI mask = static_cast< mI >( 1 );
138  mask <<= maxshift - 1;
139 
140  //set hilbert-index mask to double of matrix index mask
141  hI Imask1 = static_cast< hI >( 1ul ) << ( 2 * maxshift - 2 );
142  hI Imask2 = static_cast< hI >( 1ul ) << ( 2 * maxshift - 1 );
143 
144  //initialise inverse tables
145  bool R[2][2] = {{ false, false }, { true, true }};
146  bool C[2][2] = {{ false, true }, { true, false }};
147 
148  //loop over input bits, from most significant to least significant
149  for( ; mask != 0; mask >>= 1, Imask1 >>= 2, Imask2 >>=2 ) {
150  //calculate whether the current hilbert coordinate sets the
151  //bit at mask
152  const bool Imask1_true = (coor & Imask1) > 0;
153  const bool Imask2_true = (coor & Imask2) > 0;
154  const bool r = R[ Imask2_true ? 1 : 0 ][ Imask1_true ? 1 : 0 ];
155  const bool c = C[ Imask2_true ? 1 : 0 ][ Imask1_true ? 1 : 0 ];
156 
157 #ifdef _DEBUG
158  std::cout << (&coor) << "@" << mask << ", " << (coor & Imask2) << (coor & Imask1) << " --> " << "(" << r << ", " << c << ")" << ", R={{"
159  << R[0][0] << "," << R[0][1] << "},{" << R[1][0] << "," << R[1][1] << "}}, C={{"
160  << C[0][0] << "," << C[0][1] << "},{" << C[1][0] << "," << C[1][1] << "}}" << std::endl;
161 #endif
162 
163  if( r )
164  row |= mask; //set row index bit to 1
165  else
166  row &= ~mask; //set row index bit to 0
167  if( c )
168  col |= mask; //set column index bit to 1
169  else
170  col &= ~mask; //set column index bit to 0
171  //update inverse tables
172  if( Imask1_true == Imask2_true ) {
173  if( Imask1_true ) { //permute
174  std::swap( R[0][0], R[1][0] );
175  std::swap( C[0][0], C[1][0] );
176  } else { //swap
177  std::swap( R, C );
178  }
179  } //otherwise no table update necessary
180  }
181 
182 #ifdef _DEBUG
183  std::cout << "Decode complete: " << coor << " --> (" << row << ", " << col << ")" << std::endl;
184 #endif
185  }
186 
200  void decode( hI &cur, const I &inc, mI &row, mI &col ) {
201  //note: the decode must of course be in-tune with the encode
202  // operations in Matrix2HilbertCoordinates.cpp
203 
204  //remember old value
205  const hI old = cur;
206 
207  //get new value
208  cur += inc;
209 
210  //max shift
211  const unsigned char maxshift = 2 * sizeof( mI ) > sizeof( hI ) ? 4 * sizeof( hI ) : 8 * sizeof( mI ) ;
212 
213  //set index mask
214  mI mask = static_cast< mI >( 1 );
215  mask <<= maxshift - 1;
216 
217  //set hilbert-index mask to double of matrix index mask
218  hI Imask1 = static_cast< hI >( 1ul ) << ( 2 * maxshift - 2 );
219  hI Imask2 = static_cast< hI >( 1ul ) << ( 2 * maxshift - 1 );
220 
221  //initialise inverse tables
222  bool R[2][2] = {{ false, false }, { true, true }};
223  bool C[2][2] = {{ false, true }, { true, false }};
224 
225  //tracks whether changes are cascading
226  bool cascade = false;
227 
228 #ifdef _DEBUG
229  std::cout << "Partial decode: " << cur << std::endl;
230 #endif
231 
232  //loop over input bits, from most significant to least significant
233  for( ; mask != 0; mask >>= 1, Imask1 >>= 2, Imask2 >>=2 ) {
234  //only update when old bits are out of date
235  if( cascade || (cur & Imask1) != (old & Imask1) || (cur & Imask2) != (old & Imask2) ) {
236  //calculate whether the current hilbert
237  //coordinate sets the bit at mask
238  const bool Imask1_true = (cur & Imask1) > 0;
239  const bool Imask2_true = (cur & Imask2) > 0;
240  const bool r = R[ Imask2_true ? 1 : 0 ][ Imask1_true ? 1 : 0 ];
241  const bool c = C[ Imask2_true ? 1 : 0 ][ Imask1_true ? 1 : 0 ];
242 #ifdef _DEBUG
243  std::cout << (cur & Imask2) << (cur & Imask1) << " --> " << "(" << r << ", " << c << ")" << ", R={{"
244  << R[0][0] << "," << R[0][1] << "},{" << R[1][0] << "," << R[1][1] << "}}, C={{"
245  << C[0][0] << "," << C[0][1] << "},{" << C[1][0] << "," << C[1][1] << "}}" << std::endl;
246 #endif
247  if( r )
248  row |= mask; //set row index bit to 1
249  else
250  row &= ~mask; //set row index bit to 0
251  if( c )
252  col |= mask; //set column index bit to 1
253  else
254  col &= ~mask; //set column index bit to 0
255  //are we now at entry or exit points?
256  if( Imask1_true == Imask2_true ) {
257  //no matter where old was, it was definitely not at the same exit
258  //point, so we are sure the Hilbert orientation has changed.
259  //Therefore, changes will cascade down through the remaining bits.
260  cascade = true; //the Hilbert orientation has changed in recursion!
261  //update tables
262  if( Imask1_true ) { //permute
263  std::swap( R[0][0], R[1][0] );
264  std::swap( C[0][0], C[1][0] );
265  } else { //swap
266  std::swap( R, C );
267  }
268  } else {
269  //if old was at an entry or exit point, then again the curve
270  //orientation has changed (with respect to old),and things
271  //chancges can cascade.
272  if( ((old & Imask1) > 0) == ((old & Imask2) > 0) )
273  cascade = true;
274  }
275  } else { //even if we do not need to update row/col bits, we need to track the table
276  if( ((cur & Imask1) > 0) == ((cur & Imask2) > 0) ) {
277  if( (cur & Imask1) ) { //permute
278  std::swap( R[0][0], R[1][0] );
279  std::swap( C[0][0], C[1][0] );
280  } else { //swap
281  std::swap( R, C );
282  }
283  }
284  }
285  }
286  }
287 
288 
289  public:
290 
292  HilbertArray( const std::vector< unsigned long int > &input ) {
293  //set memory use to minimum case
294  bytes = sizeof( hI ) * 2 + sizeof( mI ) * 2 + sizeof( I* );
295 
296  //check for empty input
297  if( input.size() == 0 ) {
298  start_coor = 0;
299  curpos = NULL;
300  array = NULL;
301  } else {
302  //store increment array in hilbert-Index (I) form
303  array = new I[ input.size() - 1 ];
304  //update memory use
305  bytes += sizeof( I ) * ( input.size() - 1 );
306  //store start location in matrix-Index form
307  start_coor = input[ 0 ];
308  //fill the array from input
309  for( size_t i = 0; i < input.size() - 1; ++i )
310  array[ i ] = static_cast< I >( input[ i + 1 ] );
311  //initialise current position
312  curpos = NULL;
313  }
314  }
315 
321  virtual ULI getFirstRowIndex() {
323  return static_cast< ULI >( currow );
324  }
325 
331  virtual ULI getFirstColumnIndex() {
333  return static_cast< ULI >( curcol );
334  }
335 
345  virtual void zxa( const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end ) {
346  //check for empty matrix
347  if( v >= v_end )
348  return;
349 
350  //translate first hilbert coordinate to 2D position
352 
353  //prepare for iteration
354  curpos = array;
356 
357  //do initial muladd
358  y[ curcol ] += *v++ * x[ currow ];
359 
360  //loop over all nonzeroes
361  while( v < v_end ) {
362  //update current hilbert coordinate and current coordinates
363  decode( curcoor, *curpos++, currow, curcol );
364  //do muladd
365  y[ curcol ] += *v++ * x[ currow ];
366  }
367  }
368 
378  virtual void zax( const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end ) {
379  //check for empty matrix
380  if( v >= v_end )
381  return;
382 
383  //translate first hilbert coordinate to 2D position
384 #ifndef NDEBUG
385  currow = curcol = 0; //otherwise valgrind may think currow and curcol are uninitialised after the below decode call.
386 #endif
388 
389 #ifndef NDEBUG
390  mI checkR, checkC;
391 #endif
392 
393  //prepare for iteration
394  curpos = array;
396 
397  //do initial muladd
398  y[ currow ] += *v++ * x[ curcol ];
399 
400  //loop over all nonzeroes
401  while( v != v_end ) {
402  //update current hilbert coordinate and current coordinates
403  decode( curcoor, *curpos++, currow, curcol );
404 #ifndef NDEBUG
405  checkR = checkC = 0;
406  decode( curcoor, checkR, checkC );
407  assert( currow == checkR );
408  assert( curcol == checkC );
409  size_t check1, check2;
411  assert( check2 == curcoor );
412 #endif
413 
414  //do muladd
415  y[ currow ] += *v++ * x[ curcol ];
416  }
417  }
418 
420  virtual size_t bytesUsed() {
421  return bytes;
422  }
423 
432  virtual void moveToStart( const T *__restrict__ &x, T *__restrict__ &y, const T &v ) {
433  //translate first hilbert coordinate to 2D position
435  //do muladd
436  y[ currow ] += v * x[ curcol ];
437  //prepare for iteration
438  curpos = array;
440  }
441 
449  virtual void moveToNext( const T *__restrict__ &x, T *__restrict__ &y, const T &v ) {
450  //update current hilbert coordinate and current coordinates
451  decode( curcoor, *curpos++, currow, curcol );
452  //do muladd
453  y[ currow ] += v * x[ curcol ];
454  }
455 
457  virtual ~HilbertArray() {
458  delete [] array;
459  }
460 
461 };
462 
467 unsigned char binlog( unsigned long int x ) {
468  assert( x != 0 );
469  unsigned char ret = 0;
470  bool thereIsARemainder = x > 1 ? x & 1 : false;
471  while( (x >>= 1) > 0 ) {
472  if( !thereIsARemainder && x > 1 )
473  thereIsARemainder = x & 1;
474  ret++;
475  }
476  return ret + ( thereIsARemainder ? 1 : 0 );
477 }
478 
483 unsigned char binlog( BigInt x ) {
484  assert( !(x.high == 0 && x.low == 0) );
485  unsigned char ret = 0;
486  bool thereIsARemainder = x.low > 1 ? x.low & 1 : false;
487  if( !thereIsARemainder && x.high > 1 )
488  thereIsARemainder = x.high & 1;
489  while( (x.low >>= 1 ) > 0 ) {
490  if( !thereIsARemainder && x.low > 1 )
491  thereIsARemainder = x.low & 1;
492  ret++;
493  }
494  while( (x.high >>= 1 ) > 0 ) {
495  if( !thereIsARemainder && x.high > 1 )
496  thereIsARemainder = x.high & 1;
497  ret++;
498  }
499  return ret + ( thereIsARemainder ? 1 : 0 );
500 }
501 
503 template< typename T >
504 HilbertArrayInterface< T >* getDiffArray( const std::vector< BigInt > &values_in, const unsigned long int m, const unsigned long int n ) {
505  //handle boundary case
506  if( values_in.size() == 0 )
507  return NULL;
508 
509  //get (log2 o floor) of max matrix dimension
510  const unsigned char mSize = binlog( m ) > binlog( n ) ? binlog( m ) : binlog( n );
511 
512  //get (log2 o floor) of max Hilbert coordinate
513  std::vector< BigInt >::const_iterator it = values_in.begin();
514  BigInt maxH = *it;
515  for( ++it; it != values_in.end(); ++it ) {
516  if( maxH < *it )
517  maxH = *it;
518  }
519  const unsigned char logMaxH = binlog( maxH );
520 
521  //make values array incremental (except first value)
522  //simultaneously get (log2 o floor) of max Hilbert increment
523  it = values_in.begin() + 1;
524  unsigned long int curhigh = values_in[ 0 ].high;
525  unsigned long int curlow = values_in[ 0 ].low;
526  unsigned long int maxDiff = it->low;
527  std::vector< unsigned long int > values;
528  values.push_back( curlow );
529  for( ; it != values_in.end(); ++it ) {
530  const unsigned long int diffhigh = it->high - curhigh;
531  const unsigned long int difflow = it->low - curlow;
532  curhigh = it->high;
533  curlow = it->low;
534  if( diffhigh > 0 ) {
535  std::cerr << "Current implementation assumes increments of 64 bits or less, but a larger increment was found!" << std::endl;
536  exit( EXIT_FAILURE );
537  }
538  values.push_back( difflow );
539  if( maxDiff < difflow )
540  maxDiff = difflow;
541  }
542  const unsigned char logMaxDiff = binlog( maxDiff );
543 
544  std::cout << "Matrix index bitlength: " << static_cast< unsigned short int >( mSize ) << " (" << (m>n?m:n) << ")" << std::endl;
545  std::cout << "Hilbert coordinate bitlength: " << static_cast< unsigned short int >( logMaxH ) << " (" << maxH.high << maxH.low << ")" << std::endl;
546  std::cout << "Hilbert increment bitlength: " << static_cast< unsigned short int >( logMaxDiff ) << " (" << maxDiff << ")" << std::endl;
547 
548  //construct and return tuned version
549  if( mSize <= 8 ) { //mI is unsigned char
550  if( logMaxDiff <= 8 ) { //I is unsigned char
551  if( logMaxH <= 8 ) { //hI is unsigned char
553  } else if( logMaxH <= 16 ) {
555  } else if( logMaxH <= 32 ) {
557  } else if( logMaxH <= 64 ) {
559  }
560  } else if( logMaxDiff <= 16 ) {
561  if( logMaxH <= 8 ) { //hI is unsigned char
563  } else if( logMaxH <= 16 ) {
565  } else if( logMaxH <= 32 ) {
567  } else if( logMaxH <= 64 ) {
569  }
570  } else if( logMaxDiff <= 32 ) {
571  if( logMaxH <= 8 ) { //hI is unsigned char
573  } else if( logMaxH <= 16 ) {
575  } else if( logMaxH <= 32 ) {
577  } else if( logMaxH <= 64 ) {
579  }
580  } else if( logMaxDiff <= 64 ) {
581  if( logMaxH <= 8 ) { //hI is unsigned char
583  } else if( logMaxH <= 16 ) {
585  } else if( logMaxH <= 32 ) {
587  } else if( logMaxH <= 64 ) {
589  }
590  }
591  } else if( mSize <= 16 ) { //mI is unsigned short int
592  if( logMaxDiff <= 8 ) { //I is unsigned char
593  if( logMaxH <= 8 ) { //hI is unsigned char
595  } else if( logMaxH <= 16 ) {
597  } else if( logMaxH <= 32 ) {
599  } else if( logMaxH <= 64 ) {
601  }
602  } else if( logMaxDiff <= 16 ) {
603  if( logMaxH <= 8 ) { //hI is unsigned char
605  } else if( logMaxH <= 16 ) {
607  } else if( logMaxH <= 32 ) {
609  } else if( logMaxH <= 64 ) {
611  }
612  } else if( logMaxDiff <= 32 ) {
613  if( logMaxH <= 8 ) { //hI is unsigned char
615  } else if( logMaxH <= 16 ) {
617  } else if( logMaxH <= 32 ) {
619  } else if( logMaxH <= 64 ) {
621  }
622  } else if( logMaxDiff <= 64 ) {
623  if( logMaxH <= 8 ) { //hI is unsigned char
625  } else if( logMaxH <= 16 ) {
627  } else if( logMaxH <= 32 ) {
629  } else if( logMaxH <= 64 ) {
631  }
632  }
633  } else if( mSize <= 32 ) { //mI is unsigned int
634  if( logMaxDiff <= 8 ) { //I is unsigned char
635  if( logMaxH <= 8 ) { //hI is unsigned char
637  } else if( logMaxH <= 16 ) {
639  } else if( logMaxH <= 32 ) {
641  } else if( logMaxH <= 64 ) {
643  }
644  } else if( logMaxDiff <= 16 ) {
645  if( logMaxH <= 8 ) { //hI is unsigned char
647  } else if( logMaxH <= 16 ) {
649  } else if( logMaxH <= 32 ) {
651  } else if( logMaxH <= 64 ) {
653  }
654  } else if( logMaxDiff <= 32 ) {
655  if( logMaxH <= 8 ) { //hI is unsigned char
657  } else if( logMaxH <= 16 ) {
659  } else if( logMaxH <= 32 ) {
661  } else if( logMaxH <= 64 ) {
663  }
664  } else if( logMaxDiff <= 64 ) {
665  if( logMaxH <= 8 ) { //hI is unsigned char
667  } else if( logMaxH <= 16 ) {
669  } else if( logMaxH <= 32 ) {
671  } else if( logMaxH <= 64 ) {
673  }
674  }
675  } else if( mSize <= 64 ) { //mI is unsigned long int
676  if( logMaxDiff <= 8 ) { //I is unsigned char
677  if( logMaxH <= 8 ) { //hI is unsigned char
679  } else if( logMaxH <= 16 ) {
681  } else if( logMaxH <= 32 ) {
683  } else if( logMaxH <= 64 ) {
685  }
686  } else if( logMaxDiff <= 16 ) {
687  if( logMaxH <= 8 ) { //hI is unsigned char
689  } else if( logMaxH <= 16 ) {
691  } else if( logMaxH <= 32 ) {
693  } else if( logMaxH <= 64 ) {
695  }
696  } else if( logMaxDiff <= 32 ) {
697  if( logMaxH <= 8 ) { //hI is unsigned char
699  } else if( logMaxH <= 16 ) {
701  } else if( logMaxH <= 32 ) {
703  } else if( logMaxH <= 64 ) {
705  }
706  } else if( logMaxDiff <= 64 ) {
707  if( logMaxH <= 8 ) { //hI is unsigned char
709  } else if( logMaxH <= 16 ) {
711  } else if( logMaxH <= 32 ) {
713  } else if( logMaxH <= 64 ) {
715  }
716  }
717  } else {
718  std::cerr << "Cannot handle matrix indices requiring " << mSize << " bits!" << std::endl;
719  exit( EXIT_FAILURE );
720  }
721  return NULL;
722 }
723 
724 #endif
725 
virtual void zax(const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end)
Flat implementation of the zax.
Definition: HilbertArray.hpp:378
hI start_coor
Hilbert start coordinate.
Definition: HilbertArray.hpp:95
unsigned long int high
Most significant bits.
Definition: BigInt.hpp:41
virtual void moveToNext(const T *__restrict__ &x, T *__restrict__ &y, const T &v)
Moves this interface and the two given vectors to the next position.
Definition: HilbertArray.hpp:449
Class providing an interface to an efficient storage of a 1D array of Hilbert coordinate increments...
Definition: HilbertArray.hpp:49
mI currow
Current row position.
Definition: HilbertArray.hpp:107
A 128-bit integer, with overloaded comparison operators.
Definition: BigInt.hpp:38
virtual ~HilbertArrayInterface()
Base deconstructor.
Definition: HilbertArray.hpp:77
I *__restrict__ curpos
Current position in the array.
Definition: HilbertArray.hpp:101
virtual void zax(const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end)=0
Does a zax-operation using the moveToStart and moveToNext functionalities.
virtual ULI getFirstRowIndex()
Gets the start-location of the first nonzero in this array.
Definition: HilbertArray.hpp:321
virtual ULI getFirstRowIndex()=0
Gets the first row index.
virtual size_t bytesUsed()=0
Gets the amount of storage used.
static void IntegerToHilbert(const size_t i, const size_t j, size_t &h1, size_t &h2)
New method, October 2010.
Definition: Matrix2HilbertCoordinates.cpp:48
mI curcol
Current column position.
Definition: HilbertArray.hpp:110
void decode(hI &cur, const I &inc, mI &row, mI &col)
Translates a Hilbert coordinate into a row and column index.
Definition: HilbertArray.hpp:200
virtual ~HilbertArray()
Base deconstructor.
Definition: HilbertArray.hpp:457
I * array
Index storage array.
Definition: HilbertArray.hpp:98
virtual void moveToStart(const T *__restrict__ &x, T *__restrict__ &y, const T &v)
Moves this interface to the start location and perform a single multiply-add there.
Definition: HilbertArray.hpp:432
virtual void moveToStart(const T *__restrict__ &x, T *__restrict__ &y, const T &v)=0
Moves this interface and the two given vectors to the start location.
Actual storage implementation.
Definition: HilbertArray.hpp:90
size_t bytes
Keeps track of memory use.
Definition: HilbertArray.hpp:113
virtual size_t bytesUsed()
Definition: HilbertArray.hpp:420
HilbertArray(const std::vector< unsigned long int > &input)
Base constructor.
Definition: HilbertArray.hpp:292
virtual void zxa(const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end)=0
Does a zxa-operation using the moveToStart and moveToNext functionalities.
virtual ULI getFirstColumnIndex()
Gets the start-location of the first nonzero in this array.
Definition: HilbertArray.hpp:331
hI curcoor
Current Hilbert coordinate.
Definition: HilbertArray.hpp:104
virtual void moveToNext(const T *__restrict__ &x, T *__restrict__ &y, const T &v)=0
Moves this interface and the two given vectors to the next position.
virtual ULI getFirstColumnIndex()=0
Gets the first column index.
void decode(const hI coor, mI &row, mI &col)
Translates a Hilbert coordinate into a row and column index.
Definition: HilbertArray.hpp:122
virtual void zxa(const T *__restrict__ const &x, T *__restrict__ const &y, const T *__restrict__ &v, const T *__restrict__ const &v_end)
Flat implementation of the zax.
Definition: HilbertArray.hpp:345
unsigned long int low
Least significant bits.
Definition: BigInt.hpp:44