diff --git a/include/graphblas/base/vector.hpp b/include/graphblas/base/vector.hpp index c00ca6e53..5eb4ad83a 100644 --- a/include/graphblas/base/vector.hpp +++ b/include/graphblas/base/vector.hpp @@ -236,6 +236,28 @@ namespace grb { (void) n; } + /** + * Creates a dense ALP/GraphBLAS vector. + * + * This constructor takes an initialiser list of values that will be copied + * into this vector. The size of the vector will be equal to the number of + * elements in the initialiser list. + * + * For backends with more than one user process, the size of \a vals is the + * global vector size, and the contents of \a vals are processed using + * sequential I/O semantics. + * + * @see #grb::IOMode For the difference between sequential and parallel I/O + * modes. + * + * \note There is only a difference if there are more than one user process. + * + * @param[in] vals The values to be copied into this vector. + */ + Vector( const std::initializer_list< D > &vals ) { + (void) vals; + } + /** * Move constructor. * diff --git a/include/graphblas/bsp1d/vector.hpp b/include/graphblas/bsp1d/vector.hpp index 1e85db74e..a0d44829f 100644 --- a/include/graphblas/bsp1d/vector.hpp +++ b/include/graphblas/bsp1d/vector.hpp @@ -2377,6 +2377,67 @@ namespace grb { #endif } + /** + * Constructs a BSP1D vector. + * + * @see Full description in base backend. + * + * \internal + * This constructor initialises the local vector and synchronises the global + * vector once. + * + * TODO rewrite below logic using an iterator filter (GitHub PR 233, issue + * 228) + * \endinternal + */ + Vector( const std::initializer_list< D > &vals ) + : Vector( vals.size(), vals.size() ) + { +#ifdef _DEBUG + std::cerr << "In Vector< BSP1D >::Vector( initializer_list ) constructor\n"; +#endif + RC ret = SUCCESS; + const size_t n = vals.size(); + const internal::BSP1D_Data &data = internal::grb_BSP1D.cload(); + + // Set all the local values + for( size_t i = 0; i < vals.size(); i++ ) { + const D val = *( vals.begin() + i ); + + // check if local + // if( (i / x._b) % data.P != data.s ) { + if( data.s != + internal::Distribution< BSP1D >::global_index_to_process_id( + i, n, data.P + ) + ) { + continue; + } + + // local, so translate index and perform requested operation + const size_t local_index = + internal::Distribution< BSP1D >::global_index_to_local( i, n, data.P ); +#ifdef _DEBUG + std::cout << data.s << ", grb::setElement translates global index " + << i << " to " << local_index << "\n"; +#endif + ret = ret + ? ret + : setElement( _local, val, local_index, EXECUTE ); + } + + // Synchronise once between all processes + if( SUCCESS != + collectives< BSP1D >::allreduce( ret, operators::any_or< RC >() ) + ) { + throw std::runtime_error( "grb::Vector< BSP1D >::Vector( initializer_list ): " + "collective::allreduce failed." ); + } + + // on successful execute, sync new nnz count + updateNnz(); + } + /** * Copy constructor. * diff --git a/include/graphblas/hyperdags/io.hpp b/include/graphblas/hyperdags/io.hpp index db1f09e54..09b16634a 100644 --- a/include/graphblas/hyperdags/io.hpp +++ b/include/graphblas/hyperdags/io.hpp @@ -180,7 +180,8 @@ namespace grb { typename T > RC set( - Vector< DataType, hyperdags, Coords > &x, const T val, + Vector< DataType, hyperdags, Coords > &x, + const T val, const Phase &phase = EXECUTE, const typename std::enable_if< !grb::is_object< DataType >::value && diff --git a/include/graphblas/hyperdags/vector.hpp b/include/graphblas/hyperdags/vector.hpp index 5f422399e..02c0f7734 100644 --- a/include/graphblas/hyperdags/vector.hpp +++ b/include/graphblas/hyperdags/vector.hpp @@ -161,6 +161,15 @@ namespace grb { register_vector(); } + Vector( const std::initializer_list< T > vals ) : vector( vals ) + { +#ifdef _DEBUG + std::cout << "In Vector< hyperdags >::Vector( initializer_list )" + << " constructor\n"; +#endif + register_vector(); + } + ~Vector() { #ifdef _DEBUG std::cout << "Vector (hyperdags) destructor\n"; diff --git a/include/graphblas/nonblocking/coordinates.hpp b/include/graphblas/nonblocking/coordinates.hpp index 592d77ca1..ad9e3c670 100644 --- a/include/graphblas/nonblocking/coordinates.hpp +++ b/include/graphblas/nonblocking/coordinates.hpp @@ -265,7 +265,7 @@ namespace grb { } template< bool maybe_invalid = false > - inline void local_assignAll( ) noexcept { + inline void local_assignAll() noexcept { if( maybe_invalid || _n != _cap ) { if( _assigned != nullptr ) { assert( _stack != nullptr ); @@ -318,8 +318,21 @@ namespace grb { } } - inline void clear() noexcept { + inline void assignAll() noexcept { + // this operates on the global coordinates, not on a local view of it + #pragma omp parallel + { + size_t start, end; + config::OMP::localRange( start, end, 0, _cap ); + for( size_t i = start; i < end; ++i ) { + _assigned[ i ] = true; + _stack[ i ] = i; + } + } + _n = _cap; + } + inline void clear() noexcept { if( _n == _cap ) { #ifndef NDEBUG if( _assigned == nullptr && _cap > 0 ) { @@ -327,7 +340,6 @@ namespace grb { assert( dense_coordinates_may_not_call_clear ); } #endif - #pragma omp parallel for schedule( dynamic, config::CACHE_LINE_SIZE::value() ) for( size_t i = 0; i < _cap; ++i ) { _assigned[ i ] = false; diff --git a/include/graphblas/nonblocking/vector.hpp b/include/graphblas/nonblocking/vector.hpp index 096b58ef5..a70c48521 100644 --- a/include/graphblas/nonblocking/vector.hpp +++ b/include/graphblas/nonblocking/vector.hpp @@ -255,7 +255,14 @@ namespace grb { typedef typename Vector< D, reference, MyCoordinates >::const_iterator const_iterator; - Vector( const size_t n, const size_t nz ) : ref( n, nz ) {} + Vector( const size_t n, const size_t nz ) : ref( n, nz ) { + // pipeline execution is not required here as this is a grb::Vector + // declaration +#ifdef _DEBUG + std::cerr << "In Vector< nonblocking >::Vector( size_t, size_t )" + << " constructor\n"; +#endif + } Vector( const size_t n ) : Vector( n, n ) { @@ -266,6 +273,15 @@ namespace grb { #endif } + Vector( const std::initializer_list< D > vals ) : ref( vals ) { + // pipeline execution is not required here as this is a grb::Vector + // declaration +#ifdef _DEBUG + std::cerr << "In Vector< nonblocking >::Vector( initializer_list )" + << " constructor\n"; +#endif + } + Vector() : Vector( 0 ) {} Vector( const Vector< D, nonblocking, MyCoordinates > &x ) : diff --git a/include/graphblas/reference/vector.hpp b/include/graphblas/reference/vector.hpp index 7dd5f202e..fcd2516d8 100644 --- a/include/graphblas/reference/vector.hpp +++ b/include/graphblas/reference/vector.hpp @@ -857,6 +857,28 @@ namespace grb { #endif } + /** + * Constructs a reference vector. + * + * @see Full description in base backend. + */ + Vector( const std::initializer_list< D > &vals ) + : Vector( vals.size(), vals.size() ) + { +#ifdef _DEBUG + std::cerr << "In Vector< reference >::Vector( initializer_list )" + << " constructor\n"; +#endif + +#ifdef _H_GRB_REFERENCE_OMP_VECTOR + #pragma omp parallel for simd +#endif + for( size_t i = 0; i < vals.size(); ++i ) { + _raw[ i ] = *( vals.begin() + i ); + } + _coordinates.assignAll(); + } + /** * The default constructor creates an empty vector and should never be * used explicitly. diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 64a31013b..ab0dac498 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -300,6 +300,10 @@ add_grb_executables( adapterIterator adapterIterator.cpp BACKENDS reference reference_omp hyperdags nonblocking bsp1d hybrid ) +add_grb_executables( vectorFromListConstructor vectorFromListConstructor.cpp + BACKENDS reference reference_omp bsp1d hybrid hyperdags nonblocking +) + # the below targets test successfully when they compile -- they do not need to # be executed successfully as part of the unit test suite. diff --git a/tests/unit/eWiseLambda.cpp b/tests/unit/eWiseLambda.cpp index 48ec65088..ef98ffaca 100644 --- a/tests/unit/eWiseLambda.cpp +++ b/tests/unit/eWiseLambda.cpp @@ -49,7 +49,10 @@ void grbProgram( const void *, const size_t in_size, int &error ) { } if( !error ) { - rc = grb::eWiseLambda( [&M]( const size_t i, const size_t j, int& nz ) { nz = j; }, M ); + rc = grb::eWiseLambda( [&M]( const size_t i, const size_t j, int& nz ) { + (void) i; + nz = j; + }, M ); } if( rc != SUCCESS ) { std::cerr << "\t eWiseLambda call failed\n"; @@ -57,8 +60,8 @@ void grbProgram( const void *, const size_t in_size, int &error ) { } if( !error ) { - for(auto it: M) { - if( it.second != it.first.second ) { + for( const auto &it : M ) { + if( static_cast< size_t >(it.second) != it.first.second ) { std::cerr << "\t eWiseLambda returned incorrect result\n"; error = 15; break; diff --git a/tests/unit/unittests.sh b/tests/unit/unittests.sh index 4655ee309..5b7dfc16a 100755 --- a/tests/unit/unittests.sh +++ b/tests/unit/unittests.sh @@ -407,6 +407,12 @@ for MODE in ${MODES}; do grep 'Test OK' ${TEST_OUT_DIR}/buildVector_${MODE}_${BACKEND}_${P}_${T}.log || echo "Test FAILED" echo " " + echo ">>> [x] [ ] Testing grb::Vector( initializer_list ) constructor" + $runner ${TEST_BIN_DIR}/vectorFromListConstructor_${MODE}_${BACKEND} &> ${TEST_OUT_DIR}/vectorFromListConstructor_${MODE}_${BACKEND}_${P}_${T}.log + head -1 ${TEST_OUT_DIR}/vectorFromListConstructor_${MODE}_${BACKEND}_${P}_${T}.log + grep 'Test OK' ${TEST_OUT_DIR}/vectorFromListConstructor_${MODE}_${BACKEND}_${P}_${T}.log || echo "Test FAILED" + echo " " + echo ">>> [x] [ ] Testing grb::vectorToMatrixConverter" $runner ${TEST_BIN_DIR}/vectorToMatrix_${MODE}_${BACKEND} &> ${TEST_OUT_DIR}/vectorToMatrix_${MODE}_${BACKEND}_${P}_${T}.log head -1 ${TEST_OUT_DIR}/vectorToMatrix_${MODE}_${BACKEND}_${P}_${T}.log diff --git a/tests/unit/vectorFromListConstructor.cpp b/tests/unit/vectorFromListConstructor.cpp new file mode 100644 index 000000000..da42e85e6 --- /dev/null +++ b/tests/unit/vectorFromListConstructor.cpp @@ -0,0 +1,80 @@ + +/* + * Copyright 2021 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "graphblas.hpp" + + +using namespace grb; + +void grbProgram( const void *, const size_t in_size, int &error ) { + if( in_size != 0 ) { + std::cerr << "Unit tests called with unexpected input" << std::endl; + error = 1; + return; + } + std::vector< int > values = { 4, 7, 4, 6, 4, 7, 1, 7, 3, 6, 7, 5, 1, 8, 7 }; + grb::Vector< int > x( { 4, 7, 4, 6, 4, 7, 1, 7, 3, 6, 7, 5, 1, 8, 7 } ); + bool equals = true; + auto vector_it = x.begin(); + for( size_t i = 0; i < values.size(); i++ ) { + if( vector_it == x.end() ) { + std::cerr << "Vector iterator prematurely in end position!" << std::endl; + error = 10; + return; + } + auto position = vector_it->first; + auto value = vector_it->second; + if( i != position || values[ i ] != value ) { + std::cerr << "Expected position " << i << " value " << values[ i ] + << " but got position " << position << " value " << value + << std::endl; + equals = false; + break; + } + (void) vector_it.operator++(); + } + if( !equals ) { + std::cerr << "Vector values are not correct" << std::endl; + error = 20; + return; + } +} + +int main( int argc, char ** argv ) { + (void) argc; + std::cout << "Functional test executable: " << argv[ 0 ] << std::endl; + + int error = 0; + grb::Launcher< AUTOMATIC > launcher; + if( launcher.exec( &grbProgram, NULL, 0, error ) != SUCCESS ) { + std::cout << "Test FAILED (test failed to launch)" << std::endl; + error = 255; + } + std::cerr << std::flush; + if( error == 0 ) { + std::cout << std::flush << "Test OK" << std::endl; + } else { + std::cout << std::flush << "Test FAILED" << std::endl; + } + + // done + return error; +} +