summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/phat/algorithms/chunk_reduction.h14
-rw-r--r--include/phat/representations/bit_tree_pivot_column.h278
-rw-r--r--src/phat.cpp12
-rw-r--r--src/self_test.cpp14
4 files changed, 156 insertions, 162 deletions
diff --git a/include/phat/algorithms/chunk_reduction.h b/include/phat/algorithms/chunk_reduction.h
index 44454bb..ebba266 100644
--- a/include/phat/algorithms/chunk_reduction.h
+++ b/include/phat/algorithms/chunk_reduction.h
@@ -71,11 +71,11 @@ namespace phat {
// Phase 2+3: Simplify columns and reduce them
for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) {
// Phase 2: Simplify columns
- thread_local_storage< std::vector< index > > temp_col;
- #pragma omp parallel for schedule( guided, 1 )
+ std::vector< index > temp_col;
+ #pragma omp parallel for schedule( guided, 1 ), private( temp_col )
for( index idx = 0; idx < (index)global_columns.size(); idx++ )
if( boundary_matrix.get_dim( global_columns[ idx ] ) == cur_dim )
- _global_column_simplification( global_columns[ idx ], boundary_matrix, lowest_one_lookup, column_type, is_active, temp_col() );
+ _global_column_simplification( global_columns[ idx ], boundary_matrix, lowest_one_lookup, column_type, is_active, temp_col );
boundary_matrix.sync();
// Phase 3: Reduce columns
@@ -159,12 +159,10 @@ namespace phat {
const index nr_columns = boundary_matrix.get_num_cols();
std::vector< char > finished( nr_columns, false );
- thread_local_storage< std::vector< std::pair < index, index > > > stack_buffer;
- thread_local_storage< std::vector< index > > cur_col_values_buffer;
- #pragma omp parallel for schedule( guided, 1 )
+ std::vector< std::pair < index, index > > stack;
+ std::vector< index > cur_col_values;
+ #pragma omp parallel for schedule( guided, 1 ), private( stack, cur_col_values )
for( index idx = 0; idx < (index)global_columns.size(); idx++ ) {
- std::vector< std::pair < index, index > >& stack = stack_buffer();
- std::vector< index >& cur_col_values = cur_col_values_buffer();
bool pop_next = false;
index start_col = global_columns[ idx ];
stack.push_back( std::pair< index, index >( start_col, -1 ) );
diff --git a/include/phat/representations/bit_tree_pivot_column.h b/include/phat/representations/bit_tree_pivot_column.h
index da1e628..6bf6c3d 100644
--- a/include/phat/representations/bit_tree_pivot_column.h
+++ b/include/phat/representations/bit_tree_pivot_column.h
@@ -23,143 +23,143 @@
namespace phat {
- // This is a bitset indexed with a 64-ary tree. Each node in the index
- // has 64 bits; i-th bit says that the i-th subtree is non-empty.
- // Supports practically O(1), inplace, zero-allocation: insert, remove, max_element
- // and clear in O(number of ones in the bitset).
- // 'add_index' is still the real bottleneck in practice.
- class bit_tree_column
- {
- size_t offset; // data[i + offset] = ith block of the data-bitset
- typedef uint64_t block_type;
- std::vector< block_type > data;
- size_t debrujin_magic_table[64];
-
- enum { block_size_in_bits = 64 };
- enum { block_shift = 6 };
-
- // Some magic: http://graphics.stanford.edu/~seander/bithacks.html
- // Gets the position of the rightmost bit of 'x'. 0 means the most significant bit.
- // (-x)&x isolates the rightmost bit.
- // The whole method is much faster than calling log2i, and very comparable to using ScanBitForward/Reverse intrinsic,
- // which should be one CPU instruction, but is not portable.
- size_t rightmost_pos(const block_type value) const
- {
- return 64 - 1 - debrujin_magic_table[((value & ((uint64_t)0 - value))*0x07EDD5E59A4E28C2) >> 58];
- }
-
- public:
-
- void init(index num_cols)
- {
- const size_t debrujin_for_64_bit[64] = {
- 63, 0, 58, 1, 59, 47, 53, 2,
- 60, 39, 48, 27, 54, 33, 42, 3,
- 61, 51, 37, 40, 49, 18, 28, 20,
- 55, 30, 34, 11, 43, 14, 22, 4,
- 62, 57, 46, 52, 38, 26, 32, 41,
- 50, 36, 17, 19, 29, 10, 13, 21,
- 56, 45, 25, 31, 35, 16, 9, 12,
- 44, 24, 15, 8, 23, 7, 6, 5};
-
- std::copy(debrujin_for_64_bit, debrujin_for_64_bit+64, debrujin_magic_table);
-
- uint64_t n = 1; // in case of overflow
- size_t bottom_blocks_needed = (num_cols+block_size_in_bits-1)/block_size_in_bits;
- size_t upper_blocks = 1;
-
- // How many blocks/nodes of index needed to index the whole bitset?
- while(n * block_size_in_bits < bottom_blocks_needed)
- {
- n *= block_size_in_bits;
- upper_blocks += n;
- }
-
- offset = upper_blocks;
- data.resize(upper_blocks + bottom_blocks_needed, 0);
- }
-
- index max_index() const
- {
- if (!data[0])
- return -1;
-
- const size_t size = data.size();
- size_t n = 0;
-
- while(true)
- {
- const block_type val = data[n];
- const size_t index = rightmost_pos(val);
- const size_t newn = (n << block_shift) + index + 1;
-
- if (newn >= size)
- {
- const size_t bottom_index = n - offset;
- return (bottom_index << block_shift) + index;
- }
-
- n = newn;
- }
-
- return -1;
- }
-
- bool empty() const
- {
- return data[0] == 0;
- }
-
- void add_index(const size_t entry)
- {
- const block_type ONE = 1;
- const block_type block_modulo_mask = ((ONE << block_shift) - 1);
- size_t index_in_level = entry >> block_shift;
- size_t address = index_in_level + offset;
- size_t index_in_block = entry & block_modulo_mask;
-
- block_type mask = (ONE << (block_size_in_bits - index_in_block - 1));
-
- while(true)
- {
- data[address]^=mask;
-
- // First we check if we reached the root.
- // Also, if anyone else was in this block, we don't need to update the path up.
- if (!address || (data[address] & ~mask))
- return;
-
- index_in_block = index_in_level & block_modulo_mask;
- index_in_level >>= block_shift;
- --address;
- address >>= block_shift;
- mask = (ONE << (block_size_in_bits - index_in_block - 1));
- }
- }
-
- void get_column_and_clear(column &out)
- {
- out.clear();
- while(true)
- {
- index mx = this->max_index();
- if (mx == -1)
- break;
- out.push_back(mx);
- add_index(mx);
- }
-
- std::reverse(out.begin(), out.end());
- }
-
- void add_column(const column &col)
- {
- for (size_t i = 0; i < col.size(); ++i)
- {
- add_index(col[i]);
- }
- }
- };
-
- typedef abstract_pivot_column<bit_tree_column> bit_tree_pivot_column;
+ // This is a bitset indexed with a 64-ary tree. Each node in the index
+ // has 64 bits; i-th bit says that the i-th subtree is non-empty.
+ // Supports practically O(1), inplace, zero-allocation: insert, remove, max_element
+ // and clear in O(number of ones in the bitset).
+ // 'add_index' is still the real bottleneck in practice.
+ class bit_tree_column
+ {
+ size_t offset; // data[i + offset] = ith block of the data-bitset
+ typedef uint64_t block_type;
+ std::vector< block_type > data;
+ size_t debrujin_magic_table[64];
+
+ enum { block_size_in_bits = 64 };
+ enum { block_shift = 6 };
+
+ // Some magic: http://graphics.stanford.edu/~seander/bithacks.html
+ // Gets the position of the rightmost bit of 'x'. 0 means the most significant bit.
+ // (-x)&x isolates the rightmost bit.
+ // The whole method is much faster than calling log2i, and very comparable to using ScanBitForward/Reverse intrinsic,
+ // which should be one CPU instruction, but is not portable.
+ size_t rightmost_pos(const block_type value) const
+ {
+ return 64 - 1 - debrujin_magic_table[((value & ((uint64_t)0 - value))*0x07EDD5E59A4E28C2) >> 58];
+ }
+
+ public:
+
+ void init(index num_cols)
+ {
+ const size_t debrujin_for_64_bit[64] = {
+ 63, 0, 58, 1, 59, 47, 53, 2,
+ 60, 39, 48, 27, 54, 33, 42, 3,
+ 61, 51, 37, 40, 49, 18, 28, 20,
+ 55, 30, 34, 11, 43, 14, 22, 4,
+ 62, 57, 46, 52, 38, 26, 32, 41,
+ 50, 36, 17, 19, 29, 10, 13, 21,
+ 56, 45, 25, 31, 35, 16, 9, 12,
+ 44, 24, 15, 8, 23, 7, 6, 5};
+
+ std::copy(debrujin_for_64_bit, debrujin_for_64_bit+64, debrujin_magic_table);
+
+ uint64_t n = 1; // in case of overflow
+ size_t bottom_blocks_needed = (num_cols+block_size_in_bits-1)/block_size_in_bits;
+ size_t upper_blocks = 1;
+
+ // How many blocks/nodes of index needed to index the whole bitset?
+ while(n * block_size_in_bits < bottom_blocks_needed)
+ {
+ n *= block_size_in_bits;
+ upper_blocks += n;
+ }
+
+ offset = upper_blocks;
+ data.resize(upper_blocks + bottom_blocks_needed, 0);
+ }
+
+ index max_index() const
+ {
+ if (!data[0])
+ return -1;
+
+ const size_t size = data.size();
+ size_t n = 0;
+
+ while(true)
+ {
+ const block_type val = data[n];
+ const size_t index = rightmost_pos(val);
+ const size_t newn = (n << block_shift) + index + 1;
+
+ if (newn >= size)
+ {
+ const size_t bottom_index = n - offset;
+ return (bottom_index << block_shift) + index;
+ }
+
+ n = newn;
+ }
+
+ return -1;
+ }
+
+ bool empty() const
+ {
+ return data[0] == 0;
+ }
+
+ void add_index(const size_t entry)
+ {
+ const block_type ONE = 1;
+ const block_type block_modulo_mask = ((ONE << block_shift) - 1);
+ size_t index_in_level = entry >> block_shift;
+ size_t address = index_in_level + offset;
+ size_t index_in_block = entry & block_modulo_mask;
+
+ block_type mask = (ONE << (block_size_in_bits - index_in_block - 1));
+
+ while(true)
+ {
+ data[address]^=mask;
+
+ // First we check if we reached the root.
+ // Also, if anyone else was in this block, we don't need to update the path up.
+ if (!address || (data[address] & ~mask))
+ return;
+
+ index_in_block = index_in_level & block_modulo_mask;
+ index_in_level >>= block_shift;
+ --address;
+ address >>= block_shift;
+ mask = (ONE << (block_size_in_bits - index_in_block - 1));
+ }
+ }
+
+ void get_column_and_clear(column &out)
+ {
+ out.clear();
+ while(true)
+ {
+ index mx = this->max_index();
+ if (mx == -1)
+ break;
+ out.push_back(mx);
+ add_index(mx);
+ }
+
+ std::reverse(out.begin(), out.end());
+ }
+
+ void add_column(const column &col)
+ {
+ for (size_t i = 0; i < col.size(); ++i)
+ {
+ add_index(col[i]);
+ }
+ }
+ };
+
+ typedef abstract_pivot_column<bit_tree_column> bit_tree_pivot_column;
}
diff --git a/src/phat.cpp b/src/phat.cpp
index 6757d3c..6fec0c8 100644
--- a/src/phat.cpp
+++ b/src/phat.cpp
@@ -69,7 +69,7 @@ void parse_command_line( int argc, char** argv, bool& use_binary, Representation
else if( option == "--vec-vec" ) rep_type = VEC_VEC;
else if( option == "--vec-set" ) rep_type = VEC_SET;
else if( option == "--full-pivot" ) rep_type = FULL_PIVOT;
- else if( option == "--bit-tree-pivot" ) rep_type = BIT_TREE_PIVOT;
+ else if( option == "--bit-tree-pivot" ) rep_type = BIT_TREE_PIVOT;
else if( option == "--sparse-pivot" ) rep_type = SPARSE_PIVOT;
else if( option == "--standard" ) reduction = STANDARD;
else if( option == "--twist" ) reduction = TWIST;
@@ -86,8 +86,8 @@ void parse_command_line( int argc, char** argv, bool& use_binary, Representation
template<typename Representation, typename Algorithm>
void generic_compute_pairing( std::string input_filename,
std::string output_filename,
- bool use_binary,
- bool verbose,
+ bool use_binary,
+ bool verbose,
bool dualize ) {
phat::boundary_matrix< Representation > matrix;
@@ -95,7 +95,7 @@ void generic_compute_pairing( std::string input_filename,
double read_timer = omp_get_wtime();
if( use_binary ) {
- LOG( "Reading input file " << input_filename << " in binary mode" )
+ LOG( "Reading input file " << input_filename << " in binary mode" )
read_successful = matrix.load_binary( input_filename );
} else {
LOG( "Reading input file " << input_filename << " in ascii mode" )
@@ -165,8 +165,8 @@ int main( int argc, char** argv )
case CHUNK: CALL_GENERIC_CODE(phat::full_pivot_column, phat::chunk_reduction) break;
} break;
- case BIT_TREE_PIVOT: switch( reduction ) {
- case STANDARD: CALL_GENERIC_CODE(phat::bit_tree_pivot_column, phat::standard_reduction) break;
+ case BIT_TREE_PIVOT: switch( reduction ) {
+ case STANDARD: CALL_GENERIC_CODE(phat::bit_tree_pivot_column, phat::standard_reduction) break;
case TWIST: CALL_GENERIC_CODE(phat::bit_tree_pivot_column, phat::twist_reduction) break;
case ROW: CALL_GENERIC_CODE(phat::bit_tree_pivot_column, phat::row_reduction) break;
case CHUNK: CALL_GENERIC_CODE(phat::bit_tree_pivot_column, phat::chunk_reduction) break;
diff --git a/src/self_test.cpp b/src/self_test.cpp
index b3cddc2..2aabdc4 100644
--- a/src/self_test.cpp
+++ b/src/self_test.cpp
@@ -35,7 +35,7 @@ int main( int argc, char** argv )
typedef phat::sparse_pivot_column Sparse;
typedef phat::full_pivot_column Full;
- typedef phat::bit_tree_pivot_column BitTree;
+ typedef phat::bit_tree_pivot_column BitTree;
typedef phat::vector_vector Vec_vec;
typedef phat::vector_set Vec_set;
@@ -59,7 +59,7 @@ int main( int argc, char** argv )
phat::boundary_matrix< Full > full_boundary_matrix = boundary_matrix;
phat::compute_persistence_pairs< phat::chunk_reduction >( full_pairs, full_boundary_matrix );
- std::cout << "Running Chunk - BitTree ..." << std::endl;
+ std::cout << "Running Chunk - BitTree ..." << std::endl;
phat::persistence_pairs bit_tree_pairs;
phat::boundary_matrix< BitTree > bit_tree_boundary_matrix = boundary_matrix;
phat::compute_persistence_pairs< phat::chunk_reduction >( bit_tree_pairs, bit_tree_boundary_matrix );
@@ -86,18 +86,14 @@ int main( int argc, char** argv )
std::cerr << "Error: vec_vec and vec_set differ!" << std::endl;
error = true;
}
- if( vec_set_pairs != sparse_pairs ) {
- std::cerr << "Error: vec_set and sparse differ!" << std::endl;
+ if( vec_set_pairs != bit_tree_pairs ) {
+ std::cerr << "Error: vec_set and bit_tree differ!" << std::endl;
error = true;
}
- if( bit_tree_pairs != sparse_pairs ) {
+ if( bit_tree_pairs != sparse_pairs ) {
std::cerr << "Error: bit_tree and sparse differ!" << std::endl;
error = true;
}
- if( bit_tree_pairs != vec_set_pairs ) {
- std::cerr << "Error: bit_tree and vec_vec differ!" << std::endl;
- error = true;
- }
if( error ) return EXIT_FAILURE;
else std::cout << "All results are identical (as they should be)" << std::endl;