From 26bee43826bf3db8a2942ff2cb15cec668ff61eb Mon Sep 17 00:00:00 2001 From: Daniel Nachbaur Date: Thu, 21 Jul 2016 10:30:27 +0200 Subject: [PATCH] Add brain::Circuit::getRandomGIDs() --- brain/circuit.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- brain/circuit.h | 21 ++++++++++++++++++--- doc/Changelog.md | 2 ++ tests/circuit.cpp | 31 ++++++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 6 deletions(-) diff --git a/brain/circuit.cpp b/brain/circuit.cpp index 3cf4438..fc579ed 100644 --- a/brain/circuit.cpp +++ b/brain/circuit.cpp @@ -42,6 +42,9 @@ #ifdef BRION_USE_CXX11 # include +# include +#else +# include #endif namespace fs = boost::filesystem; @@ -118,7 +121,21 @@ class Circuit::Impl , _morphologySource( config.getMorphologySource( )) , _targetSources( config.getTargetSources( )) , _cache( lunchbox::PersistentMap::createCache( )) - {} +#ifdef BRION_USE_CXX11 + , _randomEngine( _randomDevice( )) +#endif + { + const char* seedEnv = getenv( "BRAIN_CIRCUIT_SEED" ); + if( seedEnv ) + { +#ifdef BRION_USE_CXX11 + _randomEngine.seed( std::stoul( seedEnv )); +#else + srand( atol( seedEnv )); +#endif + } + } + virtual ~Impl() {} virtual size_t getNumNeurons() const = 0; @@ -132,7 +149,7 @@ class Circuit::Impl { brain::GIDSet gids; brain::GIDSet::const_iterator hint = gids.begin(); - for( size_t i = 0; i < getNumNeurons(); ++i ) + for( uint32_t i = 0; i < getNumNeurons(); ++i ) hint = gids.insert( hint, i + 1 ); return gids; } @@ -147,6 +164,24 @@ class Circuit::Impl return brion::Target::parse( _targetParsers, target ); } + GIDSet getRandomGIDs( const float fraction, + const std::string& target ) const + { + if( fraction < 0.f || fraction > 1.f ) + LBTHROW( std::runtime_error( "Fraction for getRandomGIDs() must be " + "in the range [0,1]" )); + + const GIDSet& gids = target.empty() ? getGIDs() : getGIDs( target ); + uint32_ts randomGids( gids.begin(), gids.end( )); +#ifdef BRION_USE_CXX1 + std::shuffle( randomGids.begin(), randomGids.end(), _randomEngine ); +#else + std::random_shuffle( randomGids.begin(), randomGids.end( )); +#endif + randomGids.resize( size_t( std::ceil( randomGids.size() * fraction ))); + return GIDSet( randomGids.begin(), randomGids.end( )); + } + virtual Vector3fs getPositions( const GIDSet& gids ) const = 0; virtual size_ts getMTypes( const GIDSet& gids ) const = 0; virtual Strings getMorphologyNames() const = 0; @@ -217,6 +252,11 @@ class Circuit::Impl const brion::URIs _targetSources; mutable brion::Targets _targetParsers; lunchbox::PersistentMapPtr _cache; + +#ifdef BRION_USE_CXX11 + std::random_device _randomDevice; + std::mt19937_64 _randomEngine; +#endif }; class MVD2 : public Circuit::Impl @@ -493,6 +533,17 @@ GIDSet Circuit::getGIDs( const std::string& target ) const return _impl->getGIDs( target ); } +GIDSet Circuit::getRandomGIDs( const float fraction ) const +{ + return _impl->getRandomGIDs( fraction, "" ); +} + +GIDSet Circuit::getRandomGIDs( const float fraction, + const std::string& target ) const +{ + return _impl->getRandomGIDs( fraction, target ); +} + URIs Circuit::getMorphologyURIs( const GIDSet& gids ) const { const Strings& names = _impl->getMorphologyNames( gids ); diff --git a/brain/circuit.h b/brain/circuit.h index 4a12d88..f3fd8da 100644 --- a/brain/circuit.h +++ b/brain/circuit.h @@ -61,15 +61,30 @@ class Circuit : public boost::noncopyable BRAIN_API ~Circuit(); /** - * @return The set of GIDs for the given target name. If empty it will - * return all the GIDs held by the circuit. If the target cannot be - * found, a runtime exception is raised. + * @return The set of GIDs for the given target name. + * @throw std::runtime_error if the target cannot be found. */ BRAIN_API GIDSet getGIDs( const std::string& target ) const; /** @return All GIDs held by the circuit */ BRAIN_API GIDSet getGIDs() const; + /** + * @return A random fraction of GIDs from the given target name. + * @env BRAIN_CIRCUIT_SEED set the seed for deterministic randomness + * @throw std::runtime_error if the fraction is not in the range [0,1]. + * @throw std::runtime_error if the target cannot be found. + */ + BRAIN_API GIDSet getRandomGIDs( float fraction, + const std::string& target ) const; + + /** + * @return A random fraction of GIDs from the circuit. + * @env BRAIN_CIRCUIT_SEED set the seed for deterministic randomness + * @throw std::runtime_error if the fraction is not in the range [0,1]. + */ + BRAIN_API GIDSet getRandomGIDs( float fraction ) const; + /** @return The set of URIs to access the morphologies of the given cells */ BRAIN_API URIs getMorphologyURIs( const GIDSet& gids ) const; diff --git a/doc/Changelog.md b/doc/Changelog.md index a7b2e5a..c8108fe 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,8 @@ Changelog {#Changelog} # Release 1.9.0 (git master) +* [83](https://github.com/BlueBrain/Brion/pull/83): + Add brain::Circuit::getRandomGIDs() * [82](https://github.com/BlueBrain/Brion/pull/82): Improve performance when reading synapse attributes from non-merged files * [81](https://github.com/BlueBrain/Brion/pull/81): diff --git a/tests/circuit.cpp b/tests/circuit.cpp index acbae91..02558f6 100644 --- a/tests/circuit.cpp +++ b/tests/circuit.cpp @@ -426,4 +426,33 @@ BOOST_AUTO_TEST_CASE(compare_mvd2_mvd3) names3.begin(), names3.end( )); } -#endif +BOOST_AUTO_TEST_CASE( brain_circuit_random_gids ) +{ + const brain::Circuit circuit( brion::URI( BBP_TEST_BLUECONFIG3 )); + const brain::GIDSet& gids = circuit.getRandomGIDs( 0.1f ); + BOOST_CHECK_EQUAL( gids.size(), 100 ); + + const brain::GIDSet& gids2 = circuit.getRandomGIDs( 0.1f ); + BOOST_CHECK_EQUAL( gids2.size(), 100 ); + + bool notEqual = true; + brain::GIDSet::const_iterator it1 = gids.begin(); + brain::GIDSet::const_iterator it2 = gids2.begin(); + for( ; it1 != gids.end(); ++it1, ++it2 ) + { + if( *it1 != *it2 ) + { + notEqual = true; + break; + } + } + BOOST_CHECK( notEqual ); + + const brain::GIDSet& gids3 = circuit.getRandomGIDs( 0.5f, "Layer1" ); + BOOST_CHECK_EQUAL( gids3.size(), 10 ); + + BOOST_CHECK_THROW( circuit.getRandomGIDs( -5.f ), std::runtime_error ); + BOOST_CHECK_THROW( circuit.getRandomGIDs( 1.1f ), std::runtime_error ); +} + +#endif // BRAIN_USE_MVD3