-
Notifications
You must be signed in to change notification settings - Fork 374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve BlockVector to fix issues when sorting with recent versions of Boost #1502
Conversation
To be able to use header-only installation of Boost, without static libraries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hakonsbm Thanks for working this out! I have a few questions and suggestions. In some places I am probably just not seeing through things properly ;).
cmake/ProcessOptions.cmake
Outdated
@@ -594,6 +596,7 @@ function( NEST_PROCESS_WITH_BOOST ) | |||
set( BOOST_LIBRARIES "${Boost_LIBRARIES}" PARENT_SCOPE ) | |||
set( BOOST_INCLUDE_DIR "${Boost_INCLUDE_DIR}" PARENT_SCOPE ) | |||
set( BOOST_VERSION "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}" PARENT_SCOPE ) | |||
include_directories( ${Boost_INCLUDE_DIRS} ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a little confused here: On line 597, we have BOOST_INCLUDE_DIR
and Boost_INCLUDE_DIR
, and here we have Boost_INCLUDE_DIRS
(plural). Is this all as it should be, or is there some typo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both Boost_INCLUDE_DIR
and Boost_INCLUDE_DIRS
will probably point to the same location. However, based on the examples in the documentation, and this answer in the CMake forum, Boost_INCLUDE_DIRS
is the correct variable to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have just updated PR #1477 where I used,
include_directories( ${Boost_INCLUDE_DIR} )
should I change to
include_directories( ${Boost_INCLUDE_DIRS} )
and use
set( BOOST_INCLUDE_DIR "${Boost_INCLUDE_DIRS}" PARENT_SCOPE )
as commented by @hakonsbm ?
And just to add, BOOST_INCLUDE_DIR is a variable set on the scope above the current (PARENT_SCOPE, see manual), and the following code would not work as expected, as it will contain the previous value of tha variable.
include_directories( ${BOOST_INCLUDE_DIR} )
libnestutil/block_vector.h
Outdated
@@ -247,6 +260,9 @@ class BlockVector | |||
*/ | |||
int get_max_block_size() const; | |||
|
|||
// TODO: To make BlockVector a complete random access container, it should also implement | |||
// max_size(), rbegin(), and rend(). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should either be done within this PR if straightforward or turned into a follow-up issue, but not stay as a "TODO" comment. If turned into a follow-up issue, would it be an idea to implement these three methods now to just throw an exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have created function definitions that throw exceptions and removed the "TODO".
@@ -606,6 +640,13 @@ operator-( const const_iterator& other ) const | |||
return ( block_index_ - other.block_index_ ) * max_block_size + ( this_element_index - other_element_index ); | |||
} | |||
|
|||
template < typename value_type_, typename ref_, typename ptr_ > | |||
inline typename bv_iterator< value_type_, ref_, ptr_ >::reference bv_iterator< value_type_, ref_, ptr_ >::operator[]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit confused: Stripping the template arguments, this looks to me like bv_iterator::operator[]
. But do we really want to apply array indexing to the iterator? I'd expected it used on the container. But I may be overlooking something here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For iterators, the operator[]
is the offset dereference operator, which gets the dereferenced element shifted n
places relative to the iterator position. It is required for random access iterators.
reference.push_back( i ); | ||
} | ||
} | ||
~bv_vec_reference_fixture() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Insert empty line above
@@ -260,6 +283,119 @@ BOOST_AUTO_TEST_CASE( test_iterator_compare ) | |||
BOOST_REQUIRE( not( it_b < it_a ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to add tests for all comparison operators here?
} | ||
BOOST_REQUIRE( std::is_sorted( bv_sort.begin(), bv_sort.end() ) ); | ||
BOOST_REQUIRE( std::is_sorted( bv_perm.begin(), bv_perm.end() ) ); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment explaining why you perform both the is_sorted
and the equal
tests?
testsuite/cpptests/test_sort.h
Outdated
@@ -27,78 +27,151 @@ | |||
#include <boost/test/unit_test.hpp> | |||
|
|||
// C++ includes: | |||
#include <algorithm> | |||
#include <vector> | |||
|
|||
// Includes from libnestutil: | |||
#include "sort.h" | |||
|
|||
namespace nest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is everything put in namespace nest?
testsuite/cpptests/test_sort.h
Outdated
|
||
BOOST_AUTO_TEST_SUITE( test_sort ) | ||
|
||
/** | ||
* Tests whether two arrays with randomly generated numbers are sorted | ||
* correctly by a single call to sort. | ||
* correctly when sorting with the built-in quicksort. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"built-in" == NEST's own?
nest_quicksort( bv0, bv1 ); | ||
/** | ||
* Tests whether two arrays with randomly generated numbers are sorted | ||
* correctly when sorting with Boost. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We know that Boost switches sort algorithms between small and large containers, with a boundary at 1000 elements according to Boost::sort documentation (see boost::sort::spreadsort::detail::min_sort_size
defined in boost/sort/spreadsort/detail/constants.hpp
). The tests here should cover both cases.
- Added tests of all BlockVector iterator compararators - Add testing of sorting with small data sets
@heplesser Thanks for your review! I have addressed your comments, please have another look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hakonsbm Nicely done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
Please see my comment regarding downloading boost in travis_build.sh.
extras/travis_build.sh
Outdated
cp -fr boost_1_72_0 $HOME/.cache | ||
rm -fr boost_1_72_0 | ||
CONFIGURE_BOOST="-Dwith-boost=$HOME/.cache/boost_1_72_0" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above handles the boost library differently than, for example, music or sionlib. Is there a specific reason for this? If not, wouldn't it be better to implement this the same way? I would suggest to hide the above in a file extras/install_boost.sh, adjust .travis.yaml accordingly and wrap boost with an environment variable, same as it is for all other libraries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gtrensch The idea was to always compile with Boost, like Travis currently does. But I can implement it in a way similar to the other libraries. Should some Travis jobs not compile with Boost?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hakonsbm The static code check (the first build configuration in the travis build matrix) does not require libboost. I will make a suggestion for a change and create a PR against your branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hakonsbm I have created the PR, please check.
Handle libboost same as all other libraries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution! Approving!
Until Boost version 1.69.0,
spreadsort
usedstd::sort
for small lists (<1000 elements). But with 1.69.0 and onward it usespdqsort
from the Boost library instead. Because thepdqsort
algorithm uses some operators that neitherstd::sort
norspreadsort
uses, and because of inadequacies in theBlockVector
implementation, this caused lists to not be sorted.When sorting with
spreadsort
from the Boost library, iterators for theBlockVector
to be sorted and theBlockVector
on which the same operations are performed, are combined. The combination is implemented with theIteratorPair
iterator, which usesiterator_facade
from the Boost library. Theiterator_facade
uses a few core functions to infer operators of the iterator.The problem arose when
pdqsort
used the operatoroperator-=()
. InIteratorPair
, that operator is inferred from the functionadvance( n ) { sort_iter_ += n; perm_iter_ += n; }
Where
sort_iter_
andperm_iter_
are iterators for the twoBlockVector
s. However, foroperator-=()
,advance(n)
is called with a negativen
. The iterator ofBlockVector
didn't take into consideration that itsoperator+=(n)
could be called with a negativen
. This PR improvesBlockVector
and its iterator to take that into consideration, solving the problem.In addition, this PR
BlockVector
Fixes #1489
Fixes #1239