summaryrefslogtreecommitdiff
path: root/matching/include/phat
diff options
context:
space:
mode:
Diffstat (limited to 'matching/include/phat')
-rw-r--r--matching/include/phat/algorithms/chunk_reduction.h223
-rw-r--r--matching/include/phat/algorithms/row_reduction.h56
-rw-r--r--matching/include/phat/algorithms/spectral_sequence_reduction.h80
-rw-r--r--matching/include/phat/algorithms/standard_reduction.h47
-rw-r--r--matching/include/phat/algorithms/twist_reduction.h51
-rw-r--r--matching/include/phat/boundary_matrix.h343
-rw-r--r--matching/include/phat/compute_persistence_pairs.h128
-rw-r--r--matching/include/phat/helpers/dualize.h74
-rw-r--r--matching/include/phat/helpers/misc.h75
-rw-r--r--matching/include/phat/helpers/thread_local_storage.h52
-rw-r--r--matching/include/phat/persistence_pairs.h155
-rw-r--r--matching/include/phat/representations/abstract_pivot_column.h102
-rw-r--r--matching/include/phat/representations/bit_tree_pivot_column.h165
-rw-r--r--matching/include/phat/representations/full_pivot_column.h100
-rw-r--r--matching/include/phat/representations/heap_pivot_column.h126
-rw-r--r--matching/include/phat/representations/sparse_pivot_column.h79
-rw-r--r--matching/include/phat/representations/vector_heap.h170
-rw-r--r--matching/include/phat/representations/vector_list.h101
-rw-r--r--matching/include/phat/representations/vector_set.h99
-rw-r--r--matching/include/phat/representations/vector_vector.h107
20 files changed, 2333 insertions, 0 deletions
diff --git a/matching/include/phat/algorithms/chunk_reduction.h b/matching/include/phat/algorithms/chunk_reduction.h
new file mode 100644
index 0000000..1797023
--- /dev/null
+++ b/matching/include/phat/algorithms/chunk_reduction.h
@@ -0,0 +1,223 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class chunk_reduction {
+ public:
+ enum column_type { GLOBAL
+ , LOCAL_POSITIVE
+ , LOCAL_NEGATIVE };
+
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ if( omp_get_max_threads( ) > nr_columns )
+ omp_set_num_threads( 1 );
+
+ const dimension max_dim = boundary_matrix.get_max_dim();
+
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+ std::vector < column_type > column_type( nr_columns, GLOBAL );
+ std::vector< char > is_active( nr_columns, false );
+
+ const index chunk_size = omp_get_max_threads() == 1 ? (index)sqrt( (double)nr_columns ) : nr_columns / omp_get_max_threads();
+
+ std::vector< index > chunk_boundaries;
+ for( index cur_boundary = 0; cur_boundary < nr_columns; cur_boundary += chunk_size )
+ chunk_boundaries.push_back( cur_boundary );
+ chunk_boundaries.push_back( nr_columns );
+
+ for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) {
+ // Phase 1: Reduce chunks locally -- 1st pass
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index chunk_id = 0; chunk_id < (index)chunk_boundaries.size() - 1; chunk_id++ )
+ _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim,
+ chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id ] );
+ boundary_matrix.sync();
+
+ // Phase 1: Reduce chunks locally -- 2nd pass
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index chunk_id = 1; chunk_id < (index)chunk_boundaries.size( ) - 1; chunk_id++ )
+ _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim,
+ chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id - 1 ] );
+ boundary_matrix.sync( );
+ }
+
+ // get global columns
+ std::vector< index > global_columns;
+ for( index cur_col_idx = 0; cur_col_idx < nr_columns; cur_col_idx++ )
+ if( column_type[ cur_col_idx ] == GLOBAL )
+ global_columns.push_back( cur_col_idx );
+
+ // get active columns
+ #pragma omp parallel for
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ )
+ is_active[ global_columns[ idx ] ] = true;
+ _get_active_columns( boundary_matrix, lowest_one_lookup, column_type, global_columns, is_active );
+
+ // Phase 2+3: Simplify columns and reduce them
+ for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) {
+ // Phase 2: Simplify columns
+ 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 );
+ boundary_matrix.sync();
+
+ // Phase 3: Reduce columns
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ ) {
+ index cur_col = global_columns[ idx ];
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim && column_type[ cur_col ] == GLOBAL ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+
+ boundary_matrix.sync();
+ }
+
+ protected:
+ template< typename Representation >
+ void _local_chunk_reduction( boundary_matrix< Representation >& boundary_matrix
+ , std::vector<index>& lowest_one_lookup
+ , std::vector< column_type >& column_type
+ , const dimension cur_dim
+ , const index chunk_begin
+ , const index chunk_end
+ , const index row_begin ) {
+
+ for( index cur_col = chunk_begin; cur_col < chunk_end; cur_col++ ) {
+ if( column_type[ cur_col ] == GLOBAL && boundary_matrix.get_dim( cur_col ) == cur_dim ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one >= row_begin && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one >= row_begin ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ column_type[ cur_col ] = LOCAL_NEGATIVE;
+ column_type[ lowest_one ] = LOCAL_POSITIVE;
+ boundary_matrix.clear( lowest_one );
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+ }
+
+ template< typename Representation >
+ void _get_active_columns( const boundary_matrix< Representation >& boundary_matrix
+ , const std::vector< index >& lowest_one_lookup
+ , const std::vector< column_type >& column_type
+ , const std::vector< index >& global_columns
+ , std::vector< char >& is_active ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< char > finished( nr_columns, false );
+
+ 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++ ) {
+ bool pop_next = false;
+ index start_col = global_columns[ idx ];
+ stack.push_back( std::pair< index, index >( start_col, -1 ) );
+ while( !stack.empty() ) {
+ index cur_col = stack.back().first;
+ index prev_col = stack.back().second;
+ if( pop_next ) {
+ stack.pop_back();
+ pop_next = false;
+ if( prev_col != -1 ) {
+ if( is_active[ cur_col ] ) {
+ is_active[ prev_col ] = true;
+ }
+ if( prev_col == stack.back().first ) {
+ finished[ prev_col ] = true;
+ pop_next = true;
+ }
+ }
+ } else {
+ pop_next = true;
+ boundary_matrix.get_col( cur_col, cur_col_values );
+ for( index idx = 0; idx < (index) cur_col_values.size(); idx++ ) {
+ index cur_row = cur_col_values[ idx ];
+ if( ( column_type[ cur_row ] == GLOBAL ) ) {
+ is_active[ cur_col ] = true;
+ } else if( column_type[ cur_row ] == LOCAL_POSITIVE ) {
+ index next_col = lowest_one_lookup[ cur_row ];
+ if( next_col != cur_col && !finished[ cur_col ] ) {
+ stack.push_back( std::make_pair( next_col, cur_col ) );
+ pop_next = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ template< typename Representation >
+ void _global_column_simplification( const index col_idx
+ , boundary_matrix< Representation >& boundary_matrix
+ , const std::vector< index >& lowest_one_lookup
+ , const std::vector< column_type >& column_type
+ , const std::vector< char >& is_active
+ , std::vector< index >& temp_col )
+ {
+ temp_col.clear();
+ while( !boundary_matrix.is_empty( col_idx ) ) {
+ index cur_row = boundary_matrix.get_max_index( col_idx );
+ switch( column_type[ cur_row ] ) {
+ case GLOBAL:
+ temp_col.push_back( cur_row );
+ boundary_matrix.remove_max( col_idx );
+ break;
+ case LOCAL_NEGATIVE:
+ boundary_matrix.remove_max( col_idx );
+ break;
+ case LOCAL_POSITIVE:
+ if( is_active[ lowest_one_lookup[ cur_row ] ] )
+ boundary_matrix.add_to( lowest_one_lookup[ cur_row ], col_idx );
+ else
+ boundary_matrix.remove_max( col_idx );
+ break;
+ }
+ }
+ std::reverse( temp_col.begin(), temp_col.end() );
+ boundary_matrix.set_col( col_idx, temp_col );
+ }
+ };
+}
diff --git a/matching/include/phat/algorithms/row_reduction.h b/matching/include/phat/algorithms/row_reduction.h
new file mode 100644
index 0000000..cdd1a8f
--- /dev/null
+++ b/matching/include/phat/algorithms/row_reduction.h
@@ -0,0 +1,56 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class row_reduction {
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< std::vector< index > > lowest_one_lookup( nr_columns );
+
+ for( index cur_col = nr_columns - 1; cur_col >= 0; cur_col-- ) {
+ if( !boundary_matrix.is_empty( cur_col ) )
+ lowest_one_lookup[ boundary_matrix.get_max_index( cur_col ) ].push_back( cur_col );
+
+ if( !lowest_one_lookup[ cur_col ].empty() ) {
+ boundary_matrix.clear( cur_col );
+ boundary_matrix.finalize( cur_col );
+ std::vector< index >& cols_with_cur_lowest = lowest_one_lookup[ cur_col ];
+ index source = *min_element( cols_with_cur_lowest.begin(), cols_with_cur_lowest.end() );
+ for( index idx = 0; idx < (index)cols_with_cur_lowest.size(); idx++ ) {
+ index target = cols_with_cur_lowest[ idx ];
+ if( target != source && !boundary_matrix.is_empty( target ) ) {
+ boundary_matrix.add_to( source, target );
+ if( !boundary_matrix.is_empty( target ) ) {
+ index lowest_one_of_target = boundary_matrix.get_max_index( target );
+ lowest_one_lookup[ lowest_one_of_target ].push_back( target );
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+} \ No newline at end of file
diff --git a/matching/include/phat/algorithms/spectral_sequence_reduction.h b/matching/include/phat/algorithms/spectral_sequence_reduction.h
new file mode 100644
index 0000000..bf442e6
--- /dev/null
+++ b/matching/include/phat/algorithms/spectral_sequence_reduction.h
@@ -0,0 +1,80 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class spectral_sequence_reduction {
+ public:
+ template< typename Representation >
+ void operator () ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ //const index num_stripes = (index) sqrt( (double)nr_columns );
+ const index num_stripes = omp_get_max_threads();
+
+ index block_size = ( nr_columns % num_stripes == 0 ) ? nr_columns / num_stripes : block_size = nr_columns / num_stripes + 1;
+
+ std::vector< std::vector< index > > unreduced_cols_cur_pass( num_stripes );
+ std::vector< std::vector< index > > unreduced_cols_next_pass( num_stripes );
+
+ for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) {
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) {
+ index col_begin = cur_stripe * block_size;
+ index col_end = std::min( (cur_stripe+1) * block_size, nr_columns );
+ for( index cur_col = col_begin; cur_col < col_end; cur_col++ )
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim && boundary_matrix.get_max_index( cur_col ) != -1 )
+ unreduced_cols_cur_pass[ cur_stripe ].push_back( cur_col );
+ }
+ for( index cur_pass = 0; cur_pass < num_stripes; cur_pass++ ) {
+ boundary_matrix.sync();
+ #pragma omp parallel for schedule( guided, 1 )
+ for( int cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) {
+ index row_begin = (cur_stripe - cur_pass) * block_size;
+ index row_end = row_begin + block_size;
+ unreduced_cols_next_pass[ cur_stripe ].clear();
+ for( index idx = 0; idx < (index)unreduced_cols_cur_pass[ cur_stripe ].size(); idx++ ) {
+ index cur_col = unreduced_cols_cur_pass[ cur_stripe ][ idx ];
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one >= row_begin && lowest_one < row_end && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ if( lowest_one >= row_begin && lowest_one < row_end ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ boundary_matrix.finalize( cur_col );
+ } else {
+ unreduced_cols_next_pass[ cur_stripe ].push_back( cur_col );
+ }
+ }
+ }
+ unreduced_cols_next_pass[ cur_stripe ].swap( unreduced_cols_cur_pass[ cur_stripe ] );
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/matching/include/phat/algorithms/standard_reduction.h b/matching/include/phat/algorithms/standard_reduction.h
new file mode 100644
index 0000000..e490a5e
--- /dev/null
+++ b/matching/include/phat/algorithms/standard_reduction.h
@@ -0,0 +1,47 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class standard_reduction {
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ };
+}
+
diff --git a/matching/include/phat/algorithms/twist_reduction.h b/matching/include/phat/algorithms/twist_reduction.h
new file mode 100644
index 0000000..2357df0
--- /dev/null
+++ b/matching/include/phat/algorithms/twist_reduction.h
@@ -0,0 +1,51 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class twist_reduction {
+ public:
+ template< typename Representation >
+ void operator () ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) {
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/matching/include/phat/boundary_matrix.h b/matching/include/phat/boundary_matrix.h
new file mode 100644
index 0000000..10c66cc
--- /dev/null
+++ b/matching/include/phat/boundary_matrix.h
@@ -0,0 +1,343 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/bit_tree_pivot_column.h>
+
+// interface class for the main data structure -- implementations of the interface can be found in ./representations
+namespace phat {
+ template< class Representation = bit_tree_pivot_column >
+ class boundary_matrix
+ {
+
+ protected:
+ Representation rep;
+
+ // interface functions -- actual implementation and complexity depends on chosen @Representation template
+ public:
+ // get overall number of columns in boundary_matrix
+ index get_num_cols() const { return rep._get_num_cols(); }
+
+ // set overall number of columns in boundary_matrix
+ void set_num_cols( index nr_of_columns ) { rep._set_num_cols( nr_of_columns ); }
+
+ // get dimension of given index
+ dimension get_dim( index idx ) const { return rep._get_dim( idx ); }
+
+ // set dimension of given index
+ void set_dim( index idx, dimension dim ) { rep._set_dim( idx, dim ); }
+
+ // replaces content of @col with boundary of given index
+ void get_col( index idx, column& col ) const { col.clear(); rep._get_col( idx, col ); }
+
+ // set column @idx to the values contained in @col
+ void set_col( index idx, const column& col ) { rep._set_col( idx, col ); }
+
+ // true iff boundary of given column is empty
+ bool is_empty( index idx ) const { return rep._is_empty( idx ); }
+
+ // largest index of given column (new name for lowestOne()) -- NOT thread-safe
+ index get_max_index( index idx ) const { return rep._get_max_index( idx ); }
+
+ // removes maximal index from given column
+ void remove_max( index idx ) { rep._remove_max( idx ); }
+
+ // adds column @source to column @target'
+ void add_to( index source, index target ) { rep._add_to( source, target ); }
+
+ // clears given column
+ void clear( index idx ) { rep._clear( idx ); }
+
+ // finalizes given column
+ void finalize( index idx ) { rep._finalize( idx ); }
+
+ // syncronizes all internal data structures -- has to be called before and after any multithreaded access!
+ void sync() { rep._sync(); }
+
+ // info functions -- independent of chosen 'Representation'
+ public:
+ // maximal dimension
+ dimension get_max_dim() const {
+ dimension cur_max_dim = 0;
+ for( index idx = 0; idx < get_num_cols(); idx++ )
+ cur_max_dim = get_dim( idx ) > cur_max_dim ? get_dim( idx ) : cur_max_dim;
+ return cur_max_dim;
+ }
+
+ // number of nonzero rows for given column @idx
+ index get_num_rows( index idx ) const {
+ column cur_col;
+ get_col( idx, cur_col );
+ return cur_col.size();
+ }
+
+ // maximal number of nonzero rows of all columns
+ index get_max_col_entries() const {
+ index max_col_entries = -1;
+ const index nr_of_columns = get_num_cols();
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ max_col_entries = get_num_rows( idx ) > max_col_entries ? get_num_rows( idx ) : max_col_entries;
+ return max_col_entries;
+ }
+
+ // maximal number of nonzero cols of all rows
+ index get_max_row_entries() const {
+ size_t max_row_entries = 0;
+ const index nr_of_columns = get_num_cols();
+ std::vector< std::vector< index > > transposed_matrix( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ transposed_matrix[ temp_col[ idx ] ].push_back( cur_col );
+ }
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ max_row_entries = transposed_matrix[ idx ].size() > max_row_entries ? transposed_matrix[ idx ].size() : max_row_entries;
+ return max_row_entries;
+ }
+
+ // overall number of entries in the matrix
+ index get_num_entries() const {
+ index number_of_nonzero_entries = 0;
+ const index nr_of_columns = get_num_cols();
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ number_of_nonzero_entries += get_num_rows( idx );
+ return number_of_nonzero_entries;
+ }
+
+ // operators / constructors
+ public:
+ boundary_matrix() {};
+
+ template< class OtherRepresentation >
+ boundary_matrix( const boundary_matrix< OtherRepresentation >& other ) {
+ *this = other;
+ }
+
+ template< typename OtherRepresentation >
+ bool operator==( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const {
+ const index number_of_columns = this->get_num_cols();
+
+ if( number_of_columns != other_boundary_matrix.get_num_cols() )
+ return false;
+
+ column temp_col;
+ column other_temp_col;
+ for( index idx = 0; idx < number_of_columns; idx++ ) {
+ this->get_col( idx, temp_col );
+ other_boundary_matrix.get_col( idx, other_temp_col );
+ if( temp_col != other_temp_col || this->get_dim( idx ) != other_boundary_matrix.get_dim( idx ) )
+ return false;
+ }
+ return true;
+ }
+
+ template< typename OtherRepresentation >
+ bool operator!=( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const {
+ return !( *this == other_boundary_matrix );
+ }
+
+ template< typename OtherRepresentation >
+ boundary_matrix< Representation >& operator=( const boundary_matrix< OtherRepresentation >& other )
+ {
+ const index nr_of_columns = other.get_num_cols();
+ this->set_num_cols( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ this->set_dim( cur_col, other.get_dim( cur_col ) );
+ other.get_col( cur_col, temp_col );
+ this->set_col( cur_col, temp_col );
+ }
+
+ // by convention, always return *this
+ return *this;
+ }
+
+ // I/O -- independent of chosen 'Representation'
+ public:
+
+ // initializes boundary_matrix from (vector<vector>, vector) pair -- untested
+ template< typename index_type, typename dimemsion_type >
+ void load_vector_vector( const std::vector< std::vector< index_type > >& input_matrix, const std::vector< dimemsion_type >& input_dims ) {
+ const index nr_of_columns = (index)input_matrix.size();
+ this->set_num_cols( nr_of_columns );
+ column temp_col;
+ #pragma omp parallel for private( temp_col )
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ this->set_dim( cur_col, (dimension)input_dims[ cur_col ] );
+
+ index num_rows = input_matrix[ cur_col ].size();
+ temp_col.resize( num_rows );
+ for( index cur_row = 0; cur_row < num_rows; cur_row++ )
+ temp_col[ cur_row ] = (index)input_matrix[ cur_col ][ cur_row ];
+ this->set_col( cur_col, temp_col );
+ }
+ }
+
+ template< typename index_type, typename dimemsion_type >
+ void save_vector_vector( std::vector< std::vector< index_type > >& output_matrix, std::vector< dimemsion_type >& output_dims ) {
+ const index nr_of_columns = get_num_cols();
+ output_matrix.resize( nr_of_columns );
+ output_dims.resize( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ output_dims[ cur_col ] = (dimemsion_type)get_dim( cur_col );
+ get_col( cur_col, temp_col );
+ index num_rows = temp_col.size();
+ output_matrix[ cur_col ].clear();
+ output_matrix[ cur_col ].resize( num_rows );
+ for( index cur_row = 0; cur_row < num_rows; cur_row++ )
+ output_matrix[ cur_col ][ cur_row ] = (index_type)temp_col[ cur_row ];
+ }
+ }
+
+
+ // Loads the boundary_matrix from given file in ascii format
+ // Format: each line represents a column, first number is dimension, other numbers are the content of the column.
+ // Ignores empty lines and lines starting with a '#'.
+ bool load_ascii( std::string filename ) {
+ // first count number of columns:
+ std::string cur_line;
+ std::ifstream dummy( filename .c_str() );
+ if( dummy.fail() )
+ return false;
+
+ index number_of_columns = 0;
+ while( getline( dummy, cur_line ) ) {
+ cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1);
+ if( cur_line != "" && cur_line[ 0 ] != '#' )
+ number_of_columns++;
+
+ }
+ this->set_num_cols( number_of_columns );
+ dummy.close();
+
+ std::ifstream input_stream( filename.c_str() );
+ if( input_stream.fail() )
+ return false;
+
+ column temp_col;
+ index cur_col = -1;
+ while( getline( input_stream, cur_line ) ) {
+ cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1);
+ if( cur_line != "" && cur_line[ 0 ] != '#' ) {
+ cur_col++;
+ std::stringstream ss( cur_line );
+
+ int64_t temp_dim;
+ ss >> temp_dim;
+ this->set_dim( cur_col, (dimension) temp_dim );
+
+ int64_t temp_index;
+ temp_col.clear();
+ while( ss.good() ) {
+ ss >> temp_index;
+ temp_col.push_back( (index)temp_index );
+ }
+ std::sort( temp_col.begin(), temp_col.end() );
+ this->set_col( cur_col, temp_col );
+ }
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the boundary_matrix to given file in ascii format
+ // Format: each line represents a column, first number is dimension, other numbers are the content of the column
+ bool save_ascii( std::string filename ) {
+ std::ofstream output_stream( filename.c_str() );
+ if( output_stream.fail() )
+ return false;
+
+ const index nr_columns = this->get_num_cols();
+ column tempCol;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ output_stream << (int64_t)this->get_dim( cur_col );
+ this->get_col( cur_col, tempCol );
+ for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size(); cur_row_idx++ )
+ output_stream << " " << tempCol[ cur_row_idx ];
+ output_stream << std::endl;
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ // Loads boundary_matrix from given file
+ // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ...
+ bool load_binary( std::string filename )
+ {
+ std::ifstream input_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::in );
+ if( input_stream.fail( ) )
+ return false;
+
+ int64_t nr_columns;
+ input_stream.read( (char*)&nr_columns, sizeof( int64_t ) );
+ this->set_num_cols( (index)nr_columns );
+
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ int64_t cur_dim;
+ input_stream.read( (char*)&cur_dim, sizeof( int64_t ) );
+ this->set_dim( cur_col, (dimension)cur_dim );
+ int64_t nr_rows;
+ input_stream.read( (char*)&nr_rows, sizeof( int64_t ) );
+ temp_col.resize( ( std::size_t )nr_rows );
+ for( index idx = 0; idx < nr_rows; idx++ ) {
+ int64_t cur_row;
+ input_stream.read( (char*)&cur_row, sizeof( int64_t ) );
+ temp_col[ idx ] = (index)cur_row;
+ }
+ this->set_col( cur_col, temp_col );
+ }
+
+ input_stream.close( );
+ return true;
+ }
+
+ // Saves the boundary_matrix to given file in binary format
+ // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ...
+ bool save_binary( std::string filename )
+ {
+ std::ofstream output_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::out );
+ if( output_stream.fail( ) )
+ return false;
+
+ const int64_t nr_columns = this->get_num_cols( );
+ output_stream.write( (char*)&nr_columns, sizeof( int64_t ) );
+ column tempCol;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ int64_t cur_dim = this->get_dim( cur_col );
+ output_stream.write( (char*)&cur_dim, sizeof( int64_t ) );
+ this->get_col( cur_col, tempCol );
+ int64_t cur_nr_rows = tempCol.size( );
+ output_stream.write( (char*)&cur_nr_rows, sizeof( int64_t ) );
+ for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size( ); cur_row_idx++ ) {
+ int64_t cur_row = tempCol[ cur_row_idx ];
+ output_stream.write( (char*)&cur_row, sizeof( int64_t ) );
+ }
+ }
+
+ output_stream.close( );
+ return true;
+ }
+ };
+}
diff --git a/matching/include/phat/compute_persistence_pairs.h b/matching/include/phat/compute_persistence_pairs.h
new file mode 100644
index 0000000..48be65c
--- /dev/null
+++ b/matching/include/phat/compute_persistence_pairs.h
@@ -0,0 +1,128 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/persistence_pairs.h>
+#include <phat/boundary_matrix.h>
+#include <phat/helpers/dualize.h>
+#include <phat/algorithms/twist_reduction.h>
+
+namespace phat {
+ // Extracts persistence pairs in separate dimensions from a reduced
+ // boundary matrix representing ``double`` filtration. The pairs
+ // give persistent relative homology of the pair of filtrations.
+ // TODO: Use it with standard reduction algorithm (no template option).
+ template< typename ReductionAlgorithm, typename Representation >
+ void compute_relative_persistence_pairs(std::vector<persistence_pairs>& pairs, boundary_matrix<Representation>& boundary_matrix, const std::map<int, int>& L) {
+ ReductionAlgorithm reduce;
+ reduce(boundary_matrix);
+ std::map<int, bool> free;
+ std::map<int, int> invL;
+ for (std::map<int, int>::const_iterator it = L.begin(); it != L.end(); ++it) { invL[it->second] = it->first; }
+ for (std::vector<persistence_pairs>::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); }
+ for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) {
+ int dimension = boundary_matrix.get_dim(idx);
+ if (L.find(idx) != L.end()) { ++dimension; }
+ free[idx] = true;
+ if (!boundary_matrix.is_empty(idx)) {
+ index birth = boundary_matrix.get_max_index(idx);
+ index death = idx;
+ pairs[dimension-1].append_pair(birth, death);
+ free[birth] = false;
+ free[death] = false;
+ } else {
+ // This is an L-simplex and a (dimension+1)-dimensional cycle
+ if (L.find(idx) != L.end()) {
+ assert(dimension < pairs.size());
+ pairs[dimension].append_pair(idx, -1);
+ }
+ }
+ }
+ for (std::map<int, bool>::iterator it = free.begin(); it != free.end(); ++it) {
+ if (it->second) {
+ int dimension = boundary_matrix.get_dim(it->first);
+ if (invL.find(it->first) == invL.end() && L.find(it->first) == L.end()) {
+ assert(dimension < pairs.size());
+ pairs[dimension].append_pair(it->first, -1);
+ }
+ }
+ }
+ }
+
+ // Extracts persistence pairs in separate dimensions; expects a d-dimensional vector of persistent_pairs
+ template< typename ReductionAlgorithm, typename Representation >
+ void compute_persistence_pairs(std::vector<persistence_pairs>& pairs, boundary_matrix<Representation>& boundary_matrix) {
+ ReductionAlgorithm reduce;
+ reduce(boundary_matrix);
+ std::map<int, bool> free;
+ for (std::vector<persistence_pairs>::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); }
+ for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) {
+ int dimension = boundary_matrix.get_dim(idx);
+ free[idx] = true;
+ if (!boundary_matrix.is_empty(idx)) {
+ index birth = boundary_matrix.get_max_index(idx);
+ index death = idx;
+ pairs[dimension-1].append_pair(birth, death);
+ // Cannot be of the form (a, infinity)
+ free[birth] = false;
+ free[death] = false;
+ }
+ }
+ for (std::map<int, bool>::iterator it = free.begin(); it != free.end(); ++it) {
+ if (it->second) {
+ int dimension = boundary_matrix.get_dim(it->first);
+ pairs[dimension].append_pair(it->first, -1);
+ }
+ }
+ }
+
+ template< typename ReductionAlgorithm, typename Representation >
+ void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) {
+ ReductionAlgorithm reduce;
+ reduce( boundary_matrix );
+ pairs.clear();
+ for( index idx = 0; idx < boundary_matrix.get_num_cols(); idx++ ) {
+ if( !boundary_matrix.is_empty( idx ) ) {
+ index birth = boundary_matrix.get_max_index( idx );
+ index death = idx;
+ pairs.append_pair( birth, death );
+ }
+ }
+ }
+
+ template< typename ReductionAlgorithm, typename Representation >
+ void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) {
+
+ dualize( boundary_matrix );
+ compute_persistence_pairs< ReductionAlgorithm >( pairs, boundary_matrix );
+ dualize_persistence_pairs( pairs, boundary_matrix.get_num_cols() );
+ }
+
+ template< typename Representation >
+ void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) {
+ phat::compute_persistence_pairs< twist_reduction >( pairs, boundary_matrix );
+ }
+
+
+ template< typename Representation >
+ void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) {
+ compute_persistence_pairs_dualized< twist_reduction >( pairs, boundary_matrix );
+ }
+
+}
diff --git a/matching/include/phat/helpers/dualize.h b/matching/include/phat/helpers/dualize.h
new file mode 100644
index 0000000..5731408
--- /dev/null
+++ b/matching/include/phat/helpers/dualize.h
@@ -0,0 +1,74 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+#include <phat/persistence_pairs.h>
+
+
+namespace phat {
+ template< typename Representation >
+ void dualize( boundary_matrix< Representation >& boundary_matrix ) {
+
+ std::vector< dimension > dual_dims;
+ std::vector< std::vector< index > > dual_matrix;
+
+ index nr_of_columns = boundary_matrix.get_num_cols();
+ dual_matrix.resize( nr_of_columns );
+ dual_dims.resize( nr_of_columns );
+
+ std::vector< index > dual_sizes( nr_of_columns, 0 );
+
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ boundary_matrix.get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ dual_sizes[ nr_of_columns - 1 - temp_col[ idx ] ]++;
+ }
+
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ dual_matrix[cur_col].reserve(dual_sizes[cur_col]);
+
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ boundary_matrix.get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ dual_matrix[ nr_of_columns - 1 - temp_col[ idx ] ].push_back( nr_of_columns - 1 - cur_col );
+ }
+
+ const dimension max_dim = boundary_matrix.get_max_dim();
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ dual_dims[ nr_of_columns - 1 - cur_col ] = max_dim - boundary_matrix.get_dim( cur_col );
+
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ std::reverse( dual_matrix[ cur_col ].begin(), dual_matrix[ cur_col ].end() );
+
+ boundary_matrix.load_vector_vector( dual_matrix, dual_dims );
+ }
+
+ inline void dualize_persistence_pairs( persistence_pairs& pairs, const index n ) {
+ for (index i = 0; i < pairs.get_num_pairs(); ++i) {
+ std::pair< index, index > pair = pairs.get_pair( i );
+ pairs.set_pair( i , n - 1 - pair.second, n - 1 - pair.first);
+ }
+ }
+}
diff --git a/matching/include/phat/helpers/misc.h b/matching/include/phat/helpers/misc.h
new file mode 100644
index 0000000..3e1ed56
--- /dev/null
+++ b/matching/include/phat/helpers/misc.h
@@ -0,0 +1,75 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+// STL includes
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <set>
+#include <list>
+#include <map>
+#include <algorithm>
+#include <queue>
+#include <cassert>
+#include <sstream>
+#include <algorithm>
+#include <iomanip>
+#include <cmath>
+#include <cstdlib>
+#include <iterator>
+
+// VS2008 and below unfortunately do not support stdint.h
+#if defined(_MSC_VER)&& _MSC_VER < 1600
+ typedef __int8 int8_t;
+ typedef unsigned __int8 uint8_t;
+ typedef __int16 int16_t;
+ typedef unsigned __int16 uint16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int32 uint32_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+#else
+ #include <stdint.h>
+#endif
+
+// basic types. index can be changed to int32_t to save memory on small instances
+namespace phat {
+ typedef int64_t index;
+ typedef int8_t dimension;
+ typedef std::vector< index > column;
+}
+
+// OpenMP (proxy) functions
+#if defined _OPENMP
+ #include <omp.h>
+#else
+ #define omp_get_thread_num() 0
+ #define omp_get_max_threads() 1
+ #define omp_get_num_threads() 1
+ inline void omp_set_num_threads( int ) {};
+ #include <time.h>
+ #define omp_get_wtime() (float)clock() / (float)CLOCKS_PER_SEC
+#endif
+
+#include <phat/helpers/thread_local_storage.h>
+
+
+
diff --git a/matching/include/phat/helpers/thread_local_storage.h b/matching/include/phat/helpers/thread_local_storage.h
new file mode 100644
index 0000000..d0b5332
--- /dev/null
+++ b/matching/include/phat/helpers/thread_local_storage.h
@@ -0,0 +1,52 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+// should ideally be equal to the cache line size of the CPU
+#define PHAT_TLS_SPACING_FACTOR 64
+
+// ThreadLocalStorage with some spacing to avoid "false sharing" (see wikipedia)
+template< typename T >
+class thread_local_storage
+{
+public:
+
+ thread_local_storage() : per_thread_storage( omp_get_max_threads() * PHAT_TLS_SPACING_FACTOR ) {};
+
+ T& operator()() {
+ return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ const T& operator()() const {
+ return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ T& operator[]( int tid ) {
+ return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ const T& operator[]( int tid ) const {
+ return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+protected:
+ std::vector< T > per_thread_storage;
+};
diff --git a/matching/include/phat/persistence_pairs.h b/matching/include/phat/persistence_pairs.h
new file mode 100644
index 0000000..eafc638
--- /dev/null
+++ b/matching/include/phat/persistence_pairs.h
@@ -0,0 +1,155 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class persistence_pairs {
+
+ protected:
+ std::vector< std::pair< index, index > > pairs;
+
+ public:
+ index get_num_pairs() const {
+ return (index)pairs.size();
+ }
+
+ void append_pair( index birth, index death ) {
+ pairs.push_back( std::make_pair( birth, death ) );
+ }
+
+ std::pair< index, index > get_pair( index idx ) const {
+ return pairs[ idx ];
+ }
+
+ void set_pair( index idx, index birth, index death ) {
+ pairs[ idx ] = std::make_pair( birth, death );
+ }
+
+ void clear() {
+ pairs.clear();
+ }
+
+ void sort() {
+ std::sort( pairs.begin(), pairs.end() );
+ }
+
+ // Loads the persistence pairs from given file in asci format
+ // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ...
+ bool load_ascii( std::string filename ) {
+ std::ifstream input_stream( filename.c_str() );
+ if( input_stream.fail() )
+ return false;
+
+ int64_t nr_pairs;
+ input_stream >> nr_pairs;
+ pairs.clear();
+ for( index idx = 0; idx < nr_pairs; idx++ ) {
+ int64_t birth;
+ input_stream >> birth;
+ int64_t death;
+ input_stream >> death;
+ append_pair( (index)birth, (index)death );
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the persistence pairs to given file in binary format
+ // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ...
+ bool save_ascii( std::string filename ) {
+ std::ofstream output_stream( filename.c_str() );
+ if( output_stream.fail() )
+ return false;
+
+ this->sort();
+ output_stream << get_num_pairs() << std::endl;
+ for( std::size_t idx = 0; idx < pairs.size(); idx++ ) {
+ output_stream << pairs[idx].first << " " << pairs[idx].second << std::endl;
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ // Loads the persistence pairs from given file in binary format
+ // Format: nr_pairs % birth1 % death1 % birth2 % death2 ...
+ bool load_binary( std::string filename ) {
+ std::ifstream input_stream( filename.c_str(), std::ios_base::binary | std::ios_base::in );
+ if( input_stream.fail() )
+ return false;
+
+ int64_t nr_pairs;
+ input_stream.read( (char*)&nr_pairs, sizeof( int64_t ) );
+ for( index idx = 0; idx < nr_pairs; idx++ ) {
+ int64_t birth;
+ input_stream.read( (char*)&birth, sizeof( int64_t ) );
+ int64_t death;
+ input_stream.read( (char*)&death, sizeof( int64_t ) );
+ append_pair( (index)birth, (index)death );
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the persistence pairs to given file in binary format
+ // Format: nr_pairs % birth1 % death1 % birth2 % death2 ...
+ bool save_binary( std::string filename ) {
+ std::ofstream output_stream( filename.c_str(), std::ios_base::binary | std::ios_base::out );
+ if( output_stream.fail() )
+ return false;
+
+ this->sort();
+ int64_t nr_pairs = get_num_pairs();
+ output_stream.write( (char*)&nr_pairs, sizeof( int64_t ) );
+ for( std::size_t idx = 0; idx < pairs.size(); idx++ ) {
+ int64_t birth = pairs[ idx ].first;
+ output_stream.write( (char*)&birth, sizeof( int64_t ) );
+ int64_t death = pairs[ idx ].second;
+ output_stream.write( (char*)&death, sizeof( int64_t ) );
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ bool operator==( persistence_pairs& other_pairs ) {
+ this->sort();
+ other_pairs.sort();
+ if( pairs.size() != (std::size_t)other_pairs.get_num_pairs() )
+ return false;
+
+ for( index idx = 0; idx < (index)pairs.size(); idx++ )
+ if( get_pair( idx ) != other_pairs.get_pair( idx ) )
+ return false;
+
+ return true;
+ }
+
+ bool operator!=( persistence_pairs& other_pairs ) {
+ return !( *this == other_pairs );
+ }
+ };
+
+
+
+}
diff --git a/matching/include/phat/representations/abstract_pivot_column.h b/matching/include/phat/representations/abstract_pivot_column.h
new file mode 100644
index 0000000..e16d7a5
--- /dev/null
+++ b/matching/include/phat/representations/abstract_pivot_column.h
@@ -0,0 +1,102 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/vector_vector.h>
+
+namespace phat {
+
+ // Note: We could even make the rep generic in the underlying Const representation
+ // But I cannot imagine that anything else than vector<vector<index>> would
+ // make sense
+ template< typename PivotColumn >
+ class abstract_pivot_column : public vector_vector {
+
+ protected:
+ typedef vector_vector Base;
+ typedef PivotColumn pivot_col;
+
+ // For parallization purposes, it could be more than one full column
+ mutable thread_local_storage< pivot_col > pivot_cols;
+ mutable thread_local_storage< index > idx_of_pivot_cols;
+
+ pivot_col& get_pivot_col() const {
+ return pivot_cols();
+ }
+
+ bool is_pivot_col( index idx ) const {
+ return idx_of_pivot_cols() == idx;
+ }
+
+ void release_pivot_col() {
+ index idx = idx_of_pivot_cols();
+ if( idx != -1 ) {
+ this->matrix[ idx ].clear();
+ pivot_cols().get_col_and_clear( this->matrix[ idx ] );
+ }
+ idx_of_pivot_cols() = -1;
+ }
+
+ void make_pivot_col( index idx ) {
+ release_pivot_col();
+ idx_of_pivot_cols() = idx;
+ get_pivot_col().add_col( matrix[ idx ] );
+ }
+
+ public:
+
+ void _set_num_cols( index nr_of_cols ) {
+ #pragma omp parallel for
+ for( int tid = 0; tid < omp_get_num_threads(); tid++ ) {
+ pivot_cols[ tid ].init( nr_of_cols );
+ idx_of_pivot_cols[ tid ] = -1;
+ }
+ Base::_set_num_cols( nr_of_cols );
+ }
+
+ void _add_to( index source, index target ) {
+ if( !is_pivot_col( target ) )
+ make_pivot_col( target );
+ get_pivot_col().add_col( matrix[source] );
+ }
+
+ void _sync() {
+ #pragma omp parallel for
+ for( int tid = 0; tid < omp_get_num_threads(); tid++ )
+ release_pivot_col();
+ }
+
+ void _get_col( index idx, column& col ) const { is_pivot_col( idx ) ? get_pivot_col().get_col( col ) : Base::_get_col( idx, col ); }
+
+ bool _is_empty( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().is_empty() : Base::_is_empty( idx ); }
+
+ index _get_max_index( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().get_max_index() : Base::_get_max_index( idx ); }
+
+ void _clear( index idx ) { is_pivot_col( idx ) ? get_pivot_col().clear() : Base::_clear( idx ); }
+
+ void _set_col( index idx, const column& col ) { is_pivot_col( idx ) ? get_pivot_col().set_col( col ) : Base::_set_col( idx, col ); }
+
+ void _remove_max( index idx ) { is_pivot_col( idx ) ? get_pivot_col().remove_max() : Base::_remove_max( idx ); }
+
+ void finalize( index idx ) { Base::_finalize( idx ); }
+ };
+}
+
+
diff --git a/matching/include/phat/representations/bit_tree_pivot_column.h b/matching/include/phat/representations/bit_tree_pivot_column.h
new file mode 100644
index 0000000..4d48e88
--- /dev/null
+++ b/matching/include/phat/representations/bit_tree_pivot_column.h
@@ -0,0 +1,165 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Hubert Wagner
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+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
+ {
+ protected:
+
+ 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 & (-(int64_t)value) ) * 0x07EDD5E59A4E28C2 ) >> 58 ];
+ }
+
+ public:
+
+ void init( index num_cols ) {
+ int64_t n = 1; // in case of overflow
+ int64_t bottom_blocks_needed = ( num_cols + block_size_in_bits - 1 ) / block_size_in_bits;
+ int64_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 );
+
+ std::size_t temp_array[ 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( &temp_array[ 0 ], &temp_array[ 64 ], &debrujin_magic_table[ 0 ] );
+ }
+
+ index get_max_index() const {
+ if( !data[ 0 ] )
+ return -1;
+
+ size_t n = 0;
+ size_t newn = 0;
+ size_t index = 0;
+ while( newn < data.size() ) {
+ n = newn;
+ index = rightmost_pos( data[ n ] );
+ newn = ( n << block_shift ) + index + 1;
+ }
+
+ return ( ( n - offset ) << block_shift ) + index;
+ }
+
+ bool is_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 ) );
+
+ data[ address ] ^= mask;
+
+ // Check if we reached the root. Also, if anyone else was in this block, we don't need to update the path up.
+ while( address && !( data[ address ] & ~mask ) ) {
+ 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 ) );
+ data[ address ] ^= mask;
+ }
+ }
+
+ void get_col_and_clear( column &out ) {
+ index mx = this->get_max_index();
+ while( mx != -1 ) {
+ out.push_back( mx );
+ add_index( mx );
+ mx = this->get_max_index();
+ }
+
+ std::reverse( out.begin(), out.end() );
+ }
+
+ void add_col(const column &col) {
+ for( size_t i = 0; i < col.size(); ++i )
+ add_index(col[i]);
+ }
+
+ void clear() {
+ index mx = this->get_max_index();
+ while( mx != -1 ) {
+ add_index( mx );
+ mx = this->get_max_index();
+ }
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column<bit_tree_column> bit_tree_pivot_column;
+}
diff --git a/matching/include/phat/representations/full_pivot_column.h b/matching/include/phat/representations/full_pivot_column.h
new file mode 100644
index 0000000..c2e9e3c
--- /dev/null
+++ b/matching/include/phat/representations/full_pivot_column.h
@@ -0,0 +1,100 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class full_column {
+
+ protected:
+ std::priority_queue< index > history;
+ std::vector< char > is_in_history;
+ std::vector< char > col_bit_field;
+
+ public:
+ void init( const index total_size ) {
+ col_bit_field.resize( total_size, false );
+ is_in_history.resize( total_size, false );
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ ) {
+ add_index( col[ idx ] );
+ }
+ }
+
+ void add_index( const index idx ) {
+ if( !is_in_history[ idx ] ) {
+ history.push( idx );
+ is_in_history[ idx ] = true;
+ }
+
+ col_bit_field[ idx ] = !col_bit_field[ idx ];
+ }
+
+ index get_max_index() {
+ while( history.size() > 0 ) {
+ index topIndex = history.top();
+ if( col_bit_field[ topIndex ] ) {
+ return topIndex;
+ } else {
+ history.pop();
+ is_in_history[ topIndex ] = false;
+ }
+ }
+
+ return -1;
+ }
+
+ void get_col_and_clear( column& col ) {
+ while( !is_empty() ) {
+ col.push_back( get_max_index() );
+ add_index( get_max_index() );
+ }
+ std::reverse( col.begin(), col.end() );
+ }
+
+ bool is_empty() {
+ return (get_max_index() == -1);
+ }
+
+ void clear() {
+ while( !is_empty() )
+ add_index( get_max_index() );
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< full_column > full_pivot_column;
+}
diff --git a/matching/include/phat/representations/heap_pivot_column.h b/matching/include/phat/representations/heap_pivot_column.h
new file mode 100644
index 0000000..33cd07b
--- /dev/null
+++ b/matching/include/phat/representations/heap_pivot_column.h
@@ -0,0 +1,126 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class heap_column {
+
+ protected:
+ std::priority_queue< index > data;
+
+ column temp_col;
+ index inserts_since_last_prune;
+
+ void prune()
+ {
+ temp_col.clear( );
+ index max_index = pop_max_index( );
+ while( max_index != -1 ) {
+ temp_col.push_back( max_index );
+ max_index = pop_max_index( );
+ }
+
+ for( index idx = 0; idx < (index)temp_col.size( ); idx++ )
+ data.push( temp_col[ idx ] );
+
+ inserts_since_last_prune = 0;
+ }
+
+ index pop_max_index()
+ {
+ if( data.empty( ) )
+ return -1;
+ else {
+ index max_element = data.top( );
+ data.pop();
+ while( !data.empty( ) && data.top( ) == max_element ) {
+ data.pop( );
+ if( data.empty( ) )
+ return -1;
+ else {
+ max_element = data.top( );
+ data.pop( );
+ }
+ }
+ return max_element;
+ }
+ }
+
+ public:
+ void init( const index total_size ) {
+ inserts_since_last_prune = 0;
+ clear();
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ )
+ data.push( col[ idx ] );
+ inserts_since_last_prune += col.size( );
+ if( 2 * inserts_since_last_prune >( index ) data.size( ) )
+ prune();
+ }
+
+ index get_max_index() {
+ index max_element = pop_max_index( );
+ if( max_element == -1 )
+ return -1;
+ else {
+ data.push( max_element );
+ return max_element;
+ }
+ }
+
+ void get_col_and_clear( column& col ) {
+ col.clear();
+ index max_index = pop_max_index( );
+ while( max_index != -1 ) {
+ col.push_back( max_index );
+ max_index = pop_max_index( );
+ }
+ std::reverse( col.begin(), col.end() );
+ }
+
+ bool is_empty() {
+ return get_max_index() == -1;
+ }
+
+ void clear() {
+ data = std::priority_queue< index >();
+ }
+
+ void remove_max() {
+ pop_max_index();
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< heap_column > heap_pivot_column;
+}
diff --git a/matching/include/phat/representations/sparse_pivot_column.h b/matching/include/phat/representations/sparse_pivot_column.h
new file mode 100644
index 0000000..390fd91
--- /dev/null
+++ b/matching/include/phat/representations/sparse_pivot_column.h
@@ -0,0 +1,79 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class sparse_column {
+
+ protected:
+ std::set< index > data;
+
+ void add_index( const index idx ) {
+ std::pair< std::set< index >::iterator, bool > result = data.insert( idx );
+ if( result.second == false )
+ data.erase( result.first );
+ }
+
+ public:
+ void init( const index total_size ) {
+ data.clear();
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ )
+ add_index( col[ idx ] );
+ }
+
+ index get_max_index() {
+ return data.empty() ? -1 : *data.rbegin();
+ }
+
+ void get_col_and_clear( column& col ) {
+ col.assign( data.begin(), data.end() );
+ data.clear();
+ }
+
+ bool is_empty() {
+ return data.empty();
+ }
+
+ void clear() {
+ data.clear();
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< sparse_column > sparse_pivot_column;
+}
diff --git a/matching/include/phat/representations/vector_heap.h b/matching/include/phat/representations/vector_heap.h
new file mode 100644
index 0000000..db0420f
--- /dev/null
+++ b/matching/include/phat/representations/vector_heap.h
@@ -0,0 +1,170 @@
+/* Copyright 2013 IST Austria
+Contributed by: Jan Reininghaus
+
+This file is part of PHAT.
+
+PHAT is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PHAT is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_heap {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< column > matrix;
+
+ std::vector< index > inserts_since_last_prune;
+
+ mutable thread_local_storage< column > temp_column_buffer;
+
+ protected:
+ void _prune( index idx )
+ {
+ column& col = matrix[ idx ];
+ column& temp_col = temp_column_buffer();
+ temp_col.clear();
+ index max_index = _pop_max_index( col );
+ while( max_index != -1 ) {
+ temp_col.push_back( max_index );
+ max_index = _pop_max_index( col );
+ }
+ col = temp_col;
+ std::reverse( col.begin( ), col.end( ) );
+ std::make_heap( col.begin( ), col.end( ) );
+ inserts_since_last_prune[ idx ] = 0;
+ }
+
+ index _pop_max_index( index idx )
+ {
+ return _pop_max_index( matrix[ idx ] );
+ }
+
+ index _pop_max_index( column& col ) const
+ {
+ if( col.empty( ) )
+ return -1;
+ else {
+ index max_element = col.front( );
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ while( !col.empty( ) && col.front( ) == max_element ) {
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ if( col.empty( ) )
+ return -1;
+ else {
+ max_element = col.front( );
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ }
+ }
+ return max_element;
+ }
+ }
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols( ) const
+ {
+ return (index)matrix.size( );
+ }
+ void _set_num_cols( index nr_of_columns )
+ {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ inserts_since_last_prune.assign( nr_of_columns, 0 );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const
+ {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim )
+ {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const
+ {
+ temp_column_buffer( ) = matrix[ idx ];
+
+ index max_index = _pop_max_index( temp_column_buffer() );
+ while( max_index != -1 ) {
+ col.push_back( max_index );
+ max_index = _pop_max_index( temp_column_buffer( ) );
+ }
+ std::reverse( col.begin( ), col.end( ) );
+ }
+ void _set_col( index idx, const column& col )
+ {
+ matrix[ idx ] = col;
+ std::make_heap( matrix[ idx ].begin( ), matrix[ idx ].end( ) );
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const
+ {
+ return _get_max_index( idx ) == -1;
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const
+ {
+ column& col = const_cast< column& >( matrix[ idx ] );
+ index max_element = _pop_max_index( col );
+ col.push_back( max_element );
+ std::push_heap( col.begin( ), col.end( ) );
+ return max_element;
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx )
+ {
+ _pop_max_index( idx );
+ }
+
+ // clears given column
+ void _clear( index idx )
+ {
+ matrix[ idx ].clear( );
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync( ) {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target )
+ {
+ for( index idx = 0; idx < (index)matrix[ source ].size( ); idx++ ) {
+ matrix[ target ].push_back( matrix[ source ][ idx ] );
+ std::push_heap( matrix[ target ].begin(), matrix[ target ].end() );
+ }
+ inserts_since_last_prune[ target ] += matrix[ source ].size();
+
+ if( 2 * inserts_since_last_prune[ target ] > ( index )matrix[ target ].size() )
+ _prune( target );
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ _prune( idx );
+ }
+
+ };
+}
diff --git a/matching/include/phat/representations/vector_list.h b/matching/include/phat/representations/vector_list.h
new file mode 100644
index 0000000..ca0b5b8
--- /dev/null
+++ b/matching/include/phat/representations/vector_list.h
@@ -0,0 +1,101 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_list {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< std::list< index > > matrix;
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols() const {
+ return (index)matrix.size();
+ }
+ void _set_num_cols( index nr_of_columns ) {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim ) {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const {
+ col.clear();
+ col.reserve( matrix[idx].size() );
+ std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) );
+ }
+
+ void _set_col( index idx, const column& col ) {
+ matrix[ idx ].clear();
+ matrix[ idx ].resize( col.size() );
+ std::copy (col.begin(), col.end(), matrix[ idx ].begin() );
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const {
+ return matrix[ idx ].empty();
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const {
+ return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin();
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx ) {
+ std::list< index >::iterator it = matrix[ idx ].end();
+ it--;
+ matrix[ idx ].erase( it );
+ }
+
+ // clears given column
+ void _clear( index idx ) {
+ matrix[ idx ].clear();
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync() {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target ) {
+ std::list< index >& source_col = matrix[ source ];
+ std::list< index >& target_col = matrix[ target ];
+ std::list< index > temp_col;
+ target_col.swap( temp_col );
+ std::set_symmetric_difference( temp_col.begin(), temp_col.end(),
+ source_col.begin(), source_col.end(),
+ std::back_inserter( target_col ) );
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ }
+ };
+}
diff --git a/matching/include/phat/representations/vector_set.h b/matching/include/phat/representations/vector_set.h
new file mode 100644
index 0000000..6878a27
--- /dev/null
+++ b/matching/include/phat/representations/vector_set.h
@@ -0,0 +1,99 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_set {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< std::set< index > > matrix;
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols() const {
+ return (index)matrix.size();
+ }
+ void _set_num_cols( index nr_of_columns ) {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim ) {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const {
+ col.clear();
+ col.reserve( matrix[idx].size() );
+ std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) );
+ }
+ void _set_col( index idx, const column& col ) {
+ matrix[ idx ].clear();
+ matrix[ idx ].insert( col.begin(), col.end() );
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const {
+ return matrix[ idx ].empty();
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const {
+ return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin();
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx ) {
+ std::set< index >::iterator it = matrix[ idx ].end();
+ it--;
+ matrix[ idx ].erase( it );
+ }
+
+ // clears given column
+ void _clear( index idx ) {
+ matrix[ idx ].clear();
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync() {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target ) {
+ for( std::set< index >::iterator it = matrix[ source ].begin(); it != matrix[ source ].end(); it++ ) {
+ std::set< index >& col = matrix[ target ];
+ std::pair< std::set< index >::iterator, bool > result = col.insert( *it );
+ if( !result.second )
+ col.erase( result.first );
+ }
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ }
+
+ };
+}
diff --git a/matching/include/phat/representations/vector_vector.h b/matching/include/phat/representations/vector_vector.h
new file mode 100644
index 0000000..f111d6b
--- /dev/null
+++ b/matching/include/phat/representations/vector_vector.h
@@ -0,0 +1,107 @@
+/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_vector {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< column > matrix;
+
+ thread_local_storage< column > temp_column_buffer;
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols() const {
+ return (index)matrix.size();
+ }
+ void _set_num_cols( index nr_of_columns ) {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim ) {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const {
+ col = matrix[ idx ];
+ }
+ void _set_col( index idx, const column& col ) {
+ matrix[ idx ] = col;
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const {
+ return matrix[ idx ].empty();
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const {
+ return matrix[ idx ].empty() ? -1 : matrix[ idx ].back();
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx ) {
+ matrix[ idx ].pop_back();
+ }
+
+ // clears given column
+ void _clear( index idx ) {
+ matrix[ idx ].clear();
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync() {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target ) {
+ column& source_col = matrix[ source ];
+ column& target_col = matrix[ target ];
+ column& temp_col = temp_column_buffer();
+
+
+ size_t new_size = source_col.size() + target_col.size();
+
+ if (new_size > temp_col.size()) temp_col.resize(new_size);
+
+ std::vector<index>::iterator col_end = std::set_symmetric_difference( target_col.begin(), target_col.end(),
+ source_col.begin(), source_col.end(),
+ temp_col.begin() );
+ temp_col.erase(col_end, temp_col.end());
+
+
+ target_col.swap(temp_col);
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ column& col = matrix[ idx ];
+ column(col.begin(), col.end()).swap(col);
+ }
+ };
+}