From ba19c7c9450ab6ef00706e5f018f9956e8c0c871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= <klinkjak@fjfi.cvut.cz> Date: Tue, 12 Dec 2017 17:31:53 +0100 Subject: [PATCH] Optimizing mesh initializer, replaced EntitySeedKey with EntitySeedHash --- src/TNL/Containers/CMakeLists.txt | 2 + src/TNL/Containers/UnorderedIndexedSet.h | 62 +++++++++ src/TNL/Containers/UnorderedIndexedSet_impl.h | 130 ++++++++++++++++++ .../MeshDetails/initializer/CMakeLists.txt | 1 - .../MeshDetails/initializer/EntitySeed.h | 57 +++++++- .../MeshDetails/initializer/EntitySeedKey.h | 67 --------- .../MeshDetails/initializer/Initializer.h | 22 +-- .../SuperentityStorageInitializer.h | 4 +- .../MeshDetails/traits/MeshEntityTraits.h | 7 +- 9 files changed, 267 insertions(+), 85 deletions(-) create mode 100644 src/TNL/Containers/UnorderedIndexedSet.h create mode 100644 src/TNL/Containers/UnorderedIndexedSet_impl.h delete mode 100644 src/TNL/Meshes/MeshDetails/initializer/EntitySeedKey.h diff --git a/src/TNL/Containers/CMakeLists.txt b/src/TNL/Containers/CMakeLists.txt index 51120b929e..5e5422f128 100644 --- a/src/TNL/Containers/CMakeLists.txt +++ b/src/TNL/Containers/CMakeLists.txt @@ -7,6 +7,8 @@ set( headers Array.h IndexedMap_impl.h IndexedSet.h IndexedSet_impl.h + UnorderedIndexedSet.h + UnorderedIndexedSet_impl.h List.h List_impl.h MultiArray.h diff --git a/src/TNL/Containers/UnorderedIndexedSet.h b/src/TNL/Containers/UnorderedIndexedSet.h new file mode 100644 index 0000000000..38a1e53937 --- /dev/null +++ b/src/TNL/Containers/UnorderedIndexedSet.h @@ -0,0 +1,62 @@ +/*************************************************************************** + UnorderedIndexedSet.h - description + ------------------- + begin : Dec 12, 2017 + copyright : (C) 2017 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +#pragma once + +#include <unordered_map> +#include <ostream> + +namespace TNL { +namespace Containers { + +template< class Key, + class Index, + class Hash = std::hash< Key >, + class KeyEqual = std::equal_to< Key >, + class Allocator = std::allocator< std::pair<const Key, Index> > > +class UnorderedIndexedSet +{ +protected: + using map_type = std::unordered_map< Key, Index, Hash, KeyEqual, Allocator >; + map_type map; + +public: + using key_type = Key; + using index_type = Index; + using value_type = typename map_type::value_type; + using size_type = typename map_type::size_type; + using hasher = Hash; + using key_equal = KeyEqual; + + void clear(); + + size_type size() const; + + Index insert( const Key& key ); + + std::pair< Index, bool > try_insert( const Key& key ); + + bool find( const Key& key, Index& index ) const; + + size_type count( const Key& key ) const; + + size_type erase( const Key& key ); + + void print( std::ostream& str ) const; +}; + +template< typename Element, + typename Index > +std::ostream& operator <<( std::ostream& str, UnorderedIndexedSet< Element, Index >& set ); + +} // namespace Containers +} // namespace TNL + +#include <TNL/Containers/UnorderedIndexedSet_impl.h> diff --git a/src/TNL/Containers/UnorderedIndexedSet_impl.h b/src/TNL/Containers/UnorderedIndexedSet_impl.h new file mode 100644 index 0000000000..4402ab55cc --- /dev/null +++ b/src/TNL/Containers/UnorderedIndexedSet_impl.h @@ -0,0 +1,130 @@ +/*************************************************************************** + UnorderedIndexedSet_impl.h - description + ------------------- + begin : Feb 15, 2014 + copyright : (C) 2014 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +#pragma once + +#include <TNL/Containers/UnorderedIndexedSet.h> + +namespace TNL { +namespace Containers { + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +void +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::clear() +{ + map.clear(); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::size_type +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::size() const +{ + return map.size(); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +Index +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::insert( const Key& key ) +{ + auto iter = map.insert( value_type( key, size() ) ).first; + return iter->second; +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +std::pair< Index, bool > +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::try_insert( const Key& key ) +{ + auto pair = map.insert( value_type( key, size() ) ); + return std::pair< Index, bool >{ pair.first->second, pair.second }; +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +bool +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::find( const Key& key, Index& index ) const +{ + auto iter = map.find( Key( key ) ); + if( iter == map.end() ) + return false; + index = iter->second.index; + return true; +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::size_type +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::count( const Key& key ) const +{ + return map.count( key ); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::size_type +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::erase( const Key& key ) +{ + return map.erase( key ); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +void UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::print( std::ostream& str ) const +{ + auto iter = map.begin(); + str << iter->second.data; + iter++; + while( iter != map.end() ) + { + str << ", " << iter->second.data; + iter++; + } +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +std::ostream& operator<<( std::ostream& str, UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >& set ) +{ + set.print( str ); + return str; +} + +} // namespace Containers +} // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/initializer/CMakeLists.txt b/src/TNL/Meshes/MeshDetails/initializer/CMakeLists.txt index 9364a2817b..f452c0c022 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/CMakeLists.txt +++ b/src/TNL/Meshes/MeshDetails/initializer/CMakeLists.txt @@ -1,6 +1,5 @@ SET( headers EntityInitializer.h EntitySeed.h - EntitySeedKey.h Initializer.h SubentitySeedsCreator.h SuperentityStorageInitializer.h diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index e9b14ff177..b9d34d0701 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -17,11 +17,15 @@ #pragma once #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> -#include <TNL/Meshes/MeshDetails/initializer/EntitySeedKey.h> namespace TNL { namespace Meshes { +template< typename EntitySeed > +struct EntitySeedHash; +template< typename EntitySeed > +struct EntitySeedEq; + template< typename MeshConfig, typename EntityTopology > class EntitySeed @@ -33,7 +37,8 @@ class EntitySeed using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; using IdArrayType = Containers::StaticArray< SubvertexTraits::count, GlobalIndexType >; - using KeyType = EntitySeedKey< MeshConfig, EntityTopology >; + using HashType = EntitySeedHash< EntitySeed >; + using KeyEqual = EntitySeedEq< EntitySeed >; static String getType() { return String( "EntitySeed<>" ); } @@ -74,7 +79,8 @@ class EntitySeed< MeshConfig, Topologies::Vertex > using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; using IdArrayType = Containers::StaticArray< 1, GlobalIndexType >; - using KeyType = EntitySeedKey< MeshConfig, Topologies::Vertex >; + using HashType = EntitySeedHash< EntitySeed >; + using KeyEqual = EntitySeedEq< EntitySeed >; static String getType() { return String( "EntitySeed<>" ); } @@ -112,6 +118,49 @@ std::ostream& operator<<( std::ostream& str, const EntitySeed< MeshConfig, Entit return str; }; +template< typename EntitySeed > +struct EntitySeedHash +{ + std::size_t operator()( const EntitySeed& seed ) const + { + using LocalIndexType = typename EntitySeed::LocalIndexType; + using GlobalIndexType = typename EntitySeed::GlobalIndexType; + + // Note that we must use an associative function to combine the hashes, + // because we *want* to ignore the order of the corner IDs. + std::size_t hash = 0; + for( LocalIndexType i = 0; i < EntitySeed::getCornersCount(); i++ ) +// hash ^= std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); + hash += std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); + return hash; + } +}; + +template< typename EntitySeed > +struct EntitySeedEq +{ + bool operator()( const EntitySeed& left, const EntitySeed& right ) const + { + using IdArrayType = typename EntitySeed::IdArrayType; + + IdArrayType sortedLeft( left.getCornerIds() ); + IdArrayType sortedRight( right.getCornerIds() ); + sortedLeft.sort(); + sortedRight.sort(); + return sortedLeft == sortedRight; + } +}; + +template< typename MeshConfig > +struct EntitySeedEq< EntitySeed< MeshConfig, Topologies::Vertex > > +{ + using Seed = EntitySeed< MeshConfig, Topologies::Vertex >; + + bool operator()( const Seed& left, const Seed& right ) const + { + return left.getCornerIds() == right.getCornerIds(); + } +}; + } // namespace Meshes } // namespace TNL - diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedKey.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedKey.h deleted file mode 100644 index 8da9cb6e92..0000000000 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedKey.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - EntitySeedKey.h - description - ------------------- - begin : Feb 13, 2014 - copyright : (C) 2014 by Tomas Oberhuber et al. - email : tomas.oberhuber@fjfi.cvut.cz - ***************************************************************************/ - -/* See Copyright Notice in tnl/Copyright */ - -/*** - * Authors: - * Oberhuber Tomas, tomas.oberhuber@fjfi.cvut.cz - * Zabka Vitezslav, zabkav@gmail.com - */ - -#pragma once - -namespace TNL { -namespace Meshes { - -template< typename MeshConfig, - typename EntityTopology > -class EntitySeed; - -/**** - * Unique identification of a mesh entity by its vertices. - * Uniqueness is preserved for entities of the same type only. - */ -template< typename MeshConfig, - typename EntityTopology > -class EntitySeedKey -{ - using EntitySeedType = EntitySeed< MeshConfig, EntityTopology >; - using IdArrayType = typename EntitySeedType::IdArrayType; - -public: - EntitySeedKey( const EntitySeedType& entitySeed ) - { - for( typename IdArrayType::IndexType i = 0; - i < entitySeed.getCornersCount(); - i++ ) - this->sortedCorners[ i ] = entitySeed.getCornerIds()[ i ]; - sortedCorners.sort( ); - } - - bool operator<( const EntitySeedKey& other ) const - { - for( typename IdArrayType::IndexType i = 0; - i < IdArrayType::size; - i++) - { - if( sortedCorners[ i ] < other.sortedCorners[ i ] ) - return true; - else - if( sortedCorners[ i ] > other.sortedCorners[ i ] ) - return false; - } - return false; - } - -private: - IdArrayType sortedCorners; -}; - -} // namespace Meshes -} // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index 22f3077cb3..fe97e530ea 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -19,7 +19,6 @@ #include <TNL/Meshes/DimensionTag.h> #include <TNL/Meshes/MeshDetails/initializer/EntityInitializer.h> #include <TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h> -#include <TNL/Meshes/MeshDetails/initializer/SuperentityStorageInitializer.h> #include <TNL/Meshes/MeshDetails/MeshEntityReferenceOrientation.h> #include <TNL/Meshes/MeshDetails/initializer/EntitySeed.h> @@ -246,13 +245,14 @@ class InitializerLayer< MeshConfig, using PointArrayType = typename MeshTraitsType::PointArrayType; using SeedType = EntitySeed< MeshConfig, EntityTopology >; using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; + using SeedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedSetType; public: GlobalIndexType getEntitiesCount( InitializerType& initializer, MeshType& mesh ) { using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; - std::set< typename SeedIndexedSet::key_type > seedSet; + SeedSet seedSet; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { @@ -283,8 +283,10 @@ class InitializerLayer< MeshConfig, for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) { auto& seed = subentitySeeds[ j ]; - if( this->seedsIndexedSet.count( seed ) == 0 ) { - const GlobalIndexType entityIndex = this->seedsIndexedSet.insert( seed ); + const auto pair = this->seedsIndexedSet.try_insert( seed ); + const GlobalIndexType& entityIndex = pair.first; + if( pair.second ) { + // insertion took place, initialize the entity EntityInitializerType::initEntity( mesh.template getEntity< DimensionTag::value >( entityIndex ), entityIndex, seed, initializer ); } } @@ -331,6 +333,8 @@ class InitializerLayer< MeshConfig, using LocalIndexType = typename MeshTraitsType::LocalIndexType; using PointArrayType = typename MeshTraitsType::PointArrayType; using SeedType = EntitySeed< MeshConfig, EntityTopology >; + using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; + using SeedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedSetType; using ReferenceOrientationType = typename EntityTraitsType::ReferenceOrientationType; using ReferenceOrientationArrayType = typename EntityTraitsType::ReferenceOrientationArrayType; @@ -339,7 +343,7 @@ class InitializerLayer< MeshConfig, GlobalIndexType getEntitiesCount( InitializerType& initializer, MeshType& mesh ) { using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; - std::set< typename SeedIndexedSet::key_type > seedSet; + SeedSet seedSet; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { @@ -371,8 +375,10 @@ class InitializerLayer< MeshConfig, for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) { auto& seed = subentitySeeds[ j ]; - if( this->seedsIndexedSet.count( seed ) == 0 ) { - const GlobalIndexType entityIndex = this->seedsIndexedSet.insert( seed ); + const auto pair = this->seedsIndexedSet.try_insert( seed ); + const GlobalIndexType& entityIndex = pair.first; + if( pair.second ) { + // insertion took place, initialize the entity EntityInitializerType::initEntity( mesh.template getEntity< DimensionTag::value >( entityIndex ), entityIndex, seed, initializer ); this->referenceOrientations[ entityIndex ] = ReferenceOrientationType( seed ); } @@ -393,8 +399,6 @@ class InitializerLayer< MeshConfig, } private: - - using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; SeedIndexedSet seedsIndexedSet; ReferenceOrientationArrayType referenceOrientations; }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/SuperentityStorageInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/SuperentityStorageInitializer.h index e166f600d9..c0327785d6 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SuperentityStorageInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SuperentityStorageInitializer.h @@ -17,7 +17,7 @@ #pragma once #include <set> -#include <map> +#include <unordered_map> #include <TNL/Meshes/DimensionTag.h> #include <TNL/Meshes/MeshDetails/traits/MeshSuperentityTraits.h> @@ -86,7 +86,7 @@ public: private: using DynamicIndexSet = std::set< GlobalIndexType >; - std::map< GlobalIndexType, DynamicIndexSet > dynamicStorageNetwork; + std::unordered_map< GlobalIndexType, DynamicIndexSet > dynamicStorageNetwork; GlobalIndexType getMaxSuperentityIndex() { diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h index 31660471db..6b21bcde96 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h @@ -17,11 +17,13 @@ #pragma once #include <TNL/Containers/Array.h> -#include <TNL/Containers/IndexedSet.h> +#include <TNL/Containers/UnorderedIndexedSet.h> #include <TNL/Meshes/Topologies/SubentityVertexMap.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> #include <TNL/Meshes/MeshDetails/initializer/EntitySeed.h> +#include <unordered_set> + namespace TNL { namespace Meshes { @@ -81,7 +83,8 @@ public: using ReferenceOrientationType = MeshEntityReferenceOrientation< MeshConfig, EntityTopology >; using StorageArrayType = Containers::Array< EntityType, Device, GlobalIndexType >; - using SeedIndexedSetType = Containers::IndexedSet< typename SeedType::KeyType, GlobalIndexType >; + using SeedIndexedSetType = Containers::UnorderedIndexedSet< SeedType, GlobalIndexType, typename SeedType::HashType, typename SeedType::KeyEqual >; + using SeedSetType = std::unordered_set< typename SeedIndexedSetType::key_type, typename SeedIndexedSetType::hasher, typename SeedIndexedSetType::key_equal >; using ReferenceOrientationArrayType = Containers::Array< ReferenceOrientationType, Device, GlobalIndexType >; static constexpr bool storageEnabled = MeshConfig::entityStorage( Dimension ); -- GitLab