Home | History | Annotate | Line # | Download | only in parallel
      1 // -*- C++ -*-
      2 
      3 // Copyright (C) 2007-2024 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the terms
      7 // of the GNU General Public License as published by the Free Software
      8 // Foundation; either version 3, or (at your option) any later
      9 // version.
     10 
     11 // This library is distributed in the hope that it will be useful, but
     12 // WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 // General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /**
     26  * @file parallel/numeric
     27 *
     28  * @brief Parallel STL function calls corresponding to stl_numeric.h.
     29  * The functions defined here mainly do case switches and
     30  * call the actual parallelized versions in other files.
     31  * Inlining policy: Functions that basically only contain one function call,
     32  * are declared inline.
     33  *  This file is a GNU parallel extension to the Standard C++ Library.
     34  */
     35 
     36 // Written by Johannes Singler and Felix Putze.
     37 
     38 #ifndef _GLIBCXX_PARALLEL_NUMERIC_H
     39 #define _GLIBCXX_PARALLEL_NUMERIC_H 1
     40 
     41 #include <numeric>
     42 #include <bits/stl_function.h>
     43 #include <parallel/numericfwd.h>
     44 #include <parallel/iterator.h>
     45 #include <parallel/for_each.h>
     46 #include <parallel/for_each_selectors.h>
     47 #include <parallel/partial_sum.h>
     48 
     49 namespace std _GLIBCXX_VISIBILITY(default)
     50 {
     51 namespace __parallel
     52 {
     53   // Sequential fallback.
     54   template<typename _IIter, typename _Tp>
     55     inline _Tp
     56     accumulate(_IIter __begin, _IIter __end, _Tp __init, 
     57                __gnu_parallel::sequential_tag)
     58     { return _GLIBCXX_STD_A::accumulate(__begin, __end, __init); }
     59 
     60   template<typename _IIter, typename _Tp, typename _BinaryOperation>
     61     inline _Tp
     62     accumulate(_IIter __begin, _IIter __end, _Tp __init,
     63                _BinaryOperation __binary_op, __gnu_parallel::sequential_tag)
     64     { return _GLIBCXX_STD_A::accumulate(__begin, __end, __init, __binary_op); }
     65 
     66   // Sequential fallback for input iterator case.
     67   template<typename _IIter, typename _Tp, typename _IteratorTag>
     68     inline _Tp
     69     __accumulate_switch(_IIter __begin, _IIter __end,
     70                       _Tp __init, _IteratorTag) 
     71     { return accumulate(__begin, __end, __init,
     72 			__gnu_parallel::sequential_tag()); }
     73 
     74   template<typename _IIter, typename _Tp, typename _BinaryOperation,
     75            typename _IteratorTag>
     76     inline _Tp
     77     __accumulate_switch(_IIter __begin, _IIter __end, _Tp __init, 
     78                       _BinaryOperation __binary_op, _IteratorTag)
     79     { return accumulate(__begin, __end, __init, __binary_op, 
     80                         __gnu_parallel::sequential_tag()); }
     81 
     82   // Parallel algorithm for random access iterators.
     83   template<typename __RAIter, typename _Tp, typename _BinaryOperation>
     84     _Tp
     85     __accumulate_switch(__RAIter __begin, __RAIter __end, 
     86                       _Tp __init, _BinaryOperation __binary_op, 
     87                       random_access_iterator_tag, 
     88                       __gnu_parallel::_Parallelism __parallelism_tag)
     89     {
     90       if (_GLIBCXX_PARALLEL_CONDITION(
     91             static_cast<__gnu_parallel::_SequenceIndex>(__end - __begin)
     92             >= __gnu_parallel::_Settings::get().accumulate_minimal_n
     93             && __gnu_parallel::__is_parallel(__parallelism_tag)))
     94         {
     95           _Tp __res = __init;
     96           __gnu_parallel::__accumulate_selector<__RAIter>
     97             __my_selector;
     98           __gnu_parallel::
     99             __for_each_template_random_access_ed(__begin, __end,
    100 						 __gnu_parallel::_Nothing(),
    101 						 __my_selector,
    102 						 __gnu_parallel::
    103 						 __accumulate_binop_reduct
    104 					       <_BinaryOperation>(__binary_op),
    105 						 __res, __res, -1);
    106           return __res;
    107         }
    108       else
    109         return accumulate(__begin, __end, __init, __binary_op, 
    110                           __gnu_parallel::sequential_tag());
    111     }
    112 
    113   // Public interface.
    114   template<typename _IIter, typename _Tp>
    115     inline _Tp
    116     accumulate(_IIter __begin, _IIter __end, _Tp __init, 
    117                __gnu_parallel::_Parallelism __parallelism_tag)
    118     {
    119       typedef std::iterator_traits<_IIter> _IteratorTraits;
    120       typedef typename _IteratorTraits::value_type _ValueType;
    121       typedef typename _IteratorTraits::iterator_category _IteratorCategory;
    122 
    123       return __accumulate_switch(__begin, __end, __init,
    124 				 __gnu_parallel::_Plus<_Tp, _ValueType>(),
    125 				 _IteratorCategory(), __parallelism_tag);
    126     }
    127 
    128   template<typename _IIter, typename _Tp>
    129     inline _Tp
    130     accumulate(_IIter __begin, _IIter __end, _Tp __init)
    131     {
    132       typedef std::iterator_traits<_IIter> _IteratorTraits;
    133       typedef typename _IteratorTraits::value_type _ValueType;
    134       typedef typename _IteratorTraits::iterator_category _IteratorCategory;
    135 
    136       return __accumulate_switch(__begin, __end, __init,
    137 				 __gnu_parallel::_Plus<_Tp, _ValueType>(),
    138 				 _IteratorCategory());
    139     }
    140 
    141   template<typename _IIter, typename _Tp, typename _BinaryOperation>
    142     inline _Tp
    143     accumulate(_IIter __begin, _IIter __end, _Tp __init, 
    144                _BinaryOperation __binary_op, 
    145                __gnu_parallel::_Parallelism __parallelism_tag)
    146     {
    147       typedef iterator_traits<_IIter> _IteratorTraits;
    148       typedef typename _IteratorTraits::iterator_category _IteratorCategory;
    149       return __accumulate_switch(__begin, __end, __init, __binary_op, 
    150 				 _IteratorCategory(), __parallelism_tag);
    151     }
    152 
    153   template<typename _IIter, typename _Tp, typename _BinaryOperation>
    154     inline _Tp
    155     accumulate(_IIter __begin, _IIter __end, _Tp __init, 
    156                _BinaryOperation __binary_op) 
    157     {
    158       typedef iterator_traits<_IIter> _IteratorTraits;
    159       typedef typename _IteratorTraits::iterator_category _IteratorCategory;
    160       return __accumulate_switch(__begin, __end, __init, __binary_op, 
    161 				 _IteratorCategory());
    162     }
    163 
    164 
    165   // Sequential fallback.
    166   template<typename _IIter1, typename _IIter2, typename _Tp>
    167     inline _Tp
    168     inner_product(_IIter1 __first1, _IIter1 __last1, 
    169                   _IIter2 __first2, _Tp __init,
    170                   __gnu_parallel::sequential_tag)
    171     { return _GLIBCXX_STD_A::inner_product(
    172                                __first1, __last1, __first2, __init); }
    173 
    174   template<typename _IIter1, typename _IIter2, typename _Tp,
    175            typename _BinaryFunction1, typename _BinaryFunction2>
    176     inline _Tp
    177     inner_product(_IIter1 __first1, _IIter1 __last1,
    178                   _IIter2 __first2, _Tp __init, _BinaryFunction1 __binary_op1, 
    179                   _BinaryFunction2 __binary_op2,
    180                   __gnu_parallel::sequential_tag)
    181     { return _GLIBCXX_STD_A::inner_product(__first1, __last1, __first2, __init,
    182                                            __binary_op1, __binary_op2); }
    183 
    184   // Parallel algorithm for random access iterators.
    185   template<typename _RAIter1, typename _RAIter2,
    186            typename _Tp, typename _BinaryFunction1, typename _BinaryFunction2>
    187     _Tp
    188     __inner_product_switch(_RAIter1 __first1,
    189 			   _RAIter1 __last1,
    190 			   _RAIter2 __first2, _Tp __init,
    191 			   _BinaryFunction1 __binary_op1,
    192 			   _BinaryFunction2 __binary_op2,
    193 			   random_access_iterator_tag,
    194 			   random_access_iterator_tag,
    195 			   __gnu_parallel::_Parallelism __parallelism_tag)
    196     {
    197       if (_GLIBCXX_PARALLEL_CONDITION((__last1 - __first1)
    198                                       >= __gnu_parallel::_Settings::get().
    199                                       accumulate_minimal_n
    200                                       && __gnu_parallel::
    201                                       __is_parallel(__parallelism_tag)))
    202         {
    203           _Tp __res = __init;
    204           __gnu_parallel::
    205             __inner_product_selector<_RAIter1,
    206             _RAIter2, _Tp> __my_selector(__first1, __first2);
    207           __gnu_parallel::
    208             __for_each_template_random_access_ed(
    209                 __first1, __last1, __binary_op2, __my_selector, __binary_op1,
    210                 __res, __res, -1);
    211           return __res;
    212         }
    213       else
    214         return inner_product(__first1, __last1, __first2, __init, 
    215                              __gnu_parallel::sequential_tag());
    216     }
    217 
    218   // No parallelism for input iterators.
    219   template<typename _IIter1, typename _IIter2, typename _Tp,
    220            typename _BinaryFunction1, typename _BinaryFunction2,
    221            typename _IteratorTag1, typename _IteratorTag2>
    222     inline _Tp
    223     __inner_product_switch(_IIter1 __first1, _IIter1 __last1, 
    224 			   _IIter2 __first2, _Tp __init, 
    225 			   _BinaryFunction1 __binary_op1,
    226 			   _BinaryFunction2 __binary_op2, 
    227 			   _IteratorTag1, _IteratorTag2)
    228     { return inner_product(__first1, __last1, __first2, __init, __binary_op1,
    229 			   __binary_op2, __gnu_parallel::sequential_tag()); }
    230 
    231   template<typename _IIter1, typename _IIter2, typename _Tp,
    232            typename _BinaryFunction1, typename _BinaryFunction2>
    233     inline _Tp
    234     inner_product(_IIter1 __first1, _IIter1 __last1, 
    235                   _IIter2 __first2, _Tp __init, _BinaryFunction1 __binary_op1, 
    236                   _BinaryFunction2 __binary_op2, 
    237                   __gnu_parallel::_Parallelism __parallelism_tag)
    238     {
    239       typedef iterator_traits<_IIter1> _TraitsType1;
    240       typedef typename _TraitsType1::iterator_category _IteratorCategory1;
    241 
    242       typedef iterator_traits<_IIter2> _TraitsType2;
    243       typedef typename _TraitsType2::iterator_category _IteratorCategory2;
    244 
    245       return __inner_product_switch(__first1, __last1, __first2, __init,
    246 				    __binary_op1, __binary_op2,
    247 				    _IteratorCategory1(), _IteratorCategory2(),
    248 				    __parallelism_tag);
    249     }
    250 
    251   template<typename _IIter1, typename _IIter2, typename _Tp,
    252            typename _BinaryFunction1, typename _BinaryFunction2>
    253     inline _Tp
    254     inner_product(_IIter1 __first1, _IIter1 __last1, 
    255                   _IIter2 __first2, _Tp __init, _BinaryFunction1 __binary_op1, 
    256                   _BinaryFunction2 __binary_op2)
    257     {
    258       typedef iterator_traits<_IIter1> _TraitsType1;
    259       typedef typename _TraitsType1::iterator_category _IteratorCategory1;
    260 
    261       typedef iterator_traits<_IIter2> _TraitsType2;
    262       typedef typename _TraitsType2::iterator_category _IteratorCategory2;
    263 
    264       return __inner_product_switch(__first1, __last1, __first2, __init,
    265 				    __binary_op1, __binary_op2,
    266 				    _IteratorCategory1(),
    267 				    _IteratorCategory2());
    268     }
    269 
    270   template<typename _IIter1, typename _IIter2, typename _Tp>
    271     inline _Tp
    272     inner_product(_IIter1 __first1, _IIter1 __last1, 
    273                   _IIter2 __first2, _Tp __init, 
    274                   __gnu_parallel::_Parallelism __parallelism_tag)
    275     {
    276       typedef iterator_traits<_IIter1> _TraitsType1;
    277       typedef typename _TraitsType1::value_type _ValueType1;
    278       typedef iterator_traits<_IIter2> _TraitsType2;
    279       typedef typename _TraitsType2::value_type _ValueType2;
    280 
    281       typedef typename
    282         __gnu_parallel::_Multiplies<_ValueType1, _ValueType2>::result_type
    283         _MultipliesResultType;
    284       return __gnu_parallel::inner_product(__first1, __last1, __first2, __init,
    285                            __gnu_parallel::_Plus<_Tp, _MultipliesResultType>(),
    286                            __gnu_parallel::
    287                            _Multiplies<_ValueType1, _ValueType2>(),
    288                            __parallelism_tag);
    289     }
    290 
    291   template<typename _IIter1, typename _IIter2, typename _Tp>
    292     inline _Tp
    293     inner_product(_IIter1 __first1, _IIter1 __last1, 
    294                   _IIter2 __first2, _Tp __init)
    295     {
    296       typedef iterator_traits<_IIter1> _TraitsType1;
    297       typedef typename _TraitsType1::value_type _ValueType1;
    298       typedef iterator_traits<_IIter2> _TraitsType2;
    299       typedef typename _TraitsType2::value_type _ValueType2;
    300 
    301       typedef typename
    302         __gnu_parallel::_Multiplies<_ValueType1, _ValueType2>::result_type
    303         _MultipliesResultType;
    304       return __gnu_parallel::inner_product(__first1, __last1, __first2, __init,
    305                            __gnu_parallel::_Plus<_Tp, _MultipliesResultType>(),
    306                            __gnu_parallel::
    307                            _Multiplies<_ValueType1, _ValueType2>());
    308     }
    309 
    310   // Sequential fallback.
    311   template<typename _IIter, typename _OutputIterator>
    312     inline _OutputIterator
    313     partial_sum(_IIter __begin, _IIter __end, _OutputIterator __result,
    314                 __gnu_parallel::sequential_tag)
    315     { return _GLIBCXX_STD_A::partial_sum(__begin, __end, __result); }
    316 
    317   // Sequential fallback.
    318   template<typename _IIter, typename _OutputIterator,
    319 	   typename _BinaryOperation>
    320     inline _OutputIterator
    321     partial_sum(_IIter __begin, _IIter __end, _OutputIterator __result,
    322                 _BinaryOperation __bin_op, __gnu_parallel::sequential_tag)
    323     { return _GLIBCXX_STD_A::partial_sum(__begin, __end, __result, __bin_op); }
    324 
    325   // Sequential fallback for input iterator case.
    326   template<typename _IIter, typename _OutputIterator,
    327            typename _BinaryOperation, typename _IteratorTag1,
    328            typename _IteratorTag2>
    329     inline _OutputIterator
    330     __partial_sum_switch(_IIter __begin, _IIter __end,
    331 			 _OutputIterator __result, _BinaryOperation __bin_op,
    332 			 _IteratorTag1, _IteratorTag2)
    333     { return _GLIBCXX_STD_A::partial_sum(__begin, __end, __result, __bin_op); }
    334 
    335   // Parallel algorithm for random access iterators.
    336   template<typename _IIter, typename _OutputIterator,
    337            typename _BinaryOperation>
    338     _OutputIterator
    339     __partial_sum_switch(_IIter __begin, _IIter __end,
    340 			 _OutputIterator __result, _BinaryOperation __bin_op,
    341 			 random_access_iterator_tag,
    342 			 random_access_iterator_tag)
    343     {
    344       if (_GLIBCXX_PARALLEL_CONDITION(
    345             static_cast<__gnu_parallel::_SequenceIndex>(__end - __begin)
    346             >= __gnu_parallel::_Settings::get().partial_sum_minimal_n))
    347         return __gnu_parallel::__parallel_partial_sum(__begin, __end,
    348 						      __result, __bin_op);
    349       else
    350         return partial_sum(__begin, __end, __result, __bin_op,
    351                            __gnu_parallel::sequential_tag());
    352     }
    353 
    354   // Public interface.
    355   template<typename _IIter, typename _OutputIterator>
    356     inline _OutputIterator
    357     partial_sum(_IIter __begin, _IIter __end, _OutputIterator __result)
    358     {
    359       typedef typename iterator_traits<_IIter>::value_type _ValueType;
    360       return __gnu_parallel::partial_sum(__begin, __end,
    361                                          __result, std::plus<_ValueType>());
    362     }
    363 
    364   // Public interface
    365   template<typename _IIter, typename _OutputIterator,
    366            typename _BinaryOperation>
    367     inline _OutputIterator
    368     partial_sum(_IIter __begin, _IIter __end, _OutputIterator __result,
    369                 _BinaryOperation __binary_op)
    370     {
    371       typedef iterator_traits<_IIter> _ITraitsType;
    372       typedef typename _ITraitsType::iterator_category _IIteratorCategory;
    373 
    374       typedef iterator_traits<_OutputIterator> _OTraitsType;
    375       typedef typename _OTraitsType::iterator_category _OIterCategory;
    376 
    377       return __partial_sum_switch(__begin, __end, __result, __binary_op,
    378 				  _IIteratorCategory(), _OIterCategory());
    379     }
    380 
    381   // Sequential fallback.
    382   template<typename _IIter, typename _OutputIterator>
    383     inline _OutputIterator
    384     adjacent_difference(_IIter __begin, _IIter __end, _OutputIterator __result,
    385                         __gnu_parallel::sequential_tag)
    386     { return _GLIBCXX_STD_A::adjacent_difference(__begin, __end, __result); }
    387 
    388   // Sequential fallback.
    389   template<typename _IIter, typename _OutputIterator,
    390            typename _BinaryOperation>
    391     inline _OutputIterator
    392     adjacent_difference(_IIter __begin, _IIter __end,
    393                         _OutputIterator __result, _BinaryOperation __bin_op,
    394                         __gnu_parallel::sequential_tag)
    395     { return _GLIBCXX_STD_A::adjacent_difference(__begin, __end,
    396 						 __result, __bin_op); }
    397 
    398   // Sequential fallback for input iterator case.
    399   template<typename _IIter, typename _OutputIterator,
    400            typename _BinaryOperation, typename _IteratorTag1,
    401            typename _IteratorTag2>
    402     inline _OutputIterator
    403     __adjacent_difference_switch(_IIter __begin, _IIter __end,
    404 				 _OutputIterator __result,
    405 				 _BinaryOperation __bin_op, _IteratorTag1,
    406 				 _IteratorTag2)
    407     { return adjacent_difference(__begin, __end, __result, __bin_op,
    408                                  __gnu_parallel::sequential_tag()); }
    409 
    410   // Parallel algorithm for random access iterators.
    411   template<typename _IIter, typename _OutputIterator,
    412            typename _BinaryOperation>
    413     _OutputIterator
    414     __adjacent_difference_switch(_IIter __begin, _IIter __end,
    415 				 _OutputIterator __result,
    416 				 _BinaryOperation __bin_op,
    417 				 random_access_iterator_tag,
    418 				 random_access_iterator_tag,
    419 				 __gnu_parallel::_Parallelism
    420 				 __parallelism_tag)
    421     {
    422       if (_GLIBCXX_PARALLEL_CONDITION(
    423             static_cast<__gnu_parallel::_SequenceIndex>(__end - __begin)
    424             >= __gnu_parallel::_Settings::get().adjacent_difference_minimal_n
    425             && __gnu_parallel::__is_parallel(__parallelism_tag)))
    426         {
    427           bool __dummy = true;
    428           typedef __gnu_parallel::_IteratorPair<_IIter, _OutputIterator,
    429             random_access_iterator_tag> _ItTrip;
    430           *__result = *__begin;
    431           _ItTrip __begin_pair(__begin + 1, __result + 1),
    432             __end_pair(__end, __result + (__end - __begin));
    433           __gnu_parallel::__adjacent_difference_selector<_ItTrip>
    434                                                             __functionality;
    435           __gnu_parallel::
    436             __for_each_template_random_access_ed(
    437                 __begin_pair, __end_pair, __bin_op, __functionality,
    438                 __gnu_parallel::_DummyReduct(), __dummy, __dummy, -1);
    439           return __functionality._M_finish_iterator;
    440         }
    441       else
    442         return adjacent_difference(__begin, __end, __result, __bin_op, 
    443                                    __gnu_parallel::sequential_tag());
    444     }
    445 
    446   // Public interface.
    447   template<typename _IIter, typename _OutputIterator>
    448     inline _OutputIterator
    449     adjacent_difference(_IIter __begin, _IIter __end,
    450                         _OutputIterator __result,
    451                         __gnu_parallel::_Parallelism __parallelism_tag)
    452     {
    453       typedef iterator_traits<_IIter> _TraitsType;
    454       typedef typename _TraitsType::value_type _ValueType;
    455       return adjacent_difference(__begin, __end, __result,
    456 				 std::minus<_ValueType>(),
    457 				 __parallelism_tag);
    458     }
    459 
    460   template<typename _IIter, typename _OutputIterator>
    461     inline _OutputIterator
    462     adjacent_difference(_IIter __begin, _IIter __end,
    463                         _OutputIterator __result)
    464     {
    465       typedef iterator_traits<_IIter> _TraitsType;
    466       typedef typename _TraitsType::value_type _ValueType;
    467       return adjacent_difference(__begin, __end, __result,
    468 				 std::minus<_ValueType>());
    469     }
    470 
    471   template<typename _IIter, typename _OutputIterator,
    472            typename _BinaryOperation>
    473     inline _OutputIterator
    474     adjacent_difference(_IIter __begin, _IIter __end,
    475                         _OutputIterator __result, _BinaryOperation __binary_op,
    476                         __gnu_parallel::_Parallelism __parallelism_tag)
    477     {
    478       typedef iterator_traits<_IIter> _ITraitsType;
    479       typedef typename _ITraitsType::iterator_category _IIteratorCategory;
    480 
    481       typedef iterator_traits<_OutputIterator> _OTraitsType;
    482       typedef typename _OTraitsType::iterator_category _OIterCategory;
    483 
    484       return __adjacent_difference_switch(__begin, __end, __result,
    485 					  __binary_op,
    486 					  _IIteratorCategory(),
    487 					  _OIterCategory(),
    488 					  __parallelism_tag);
    489     }
    490 
    491   template<typename _IIter, typename _OutputIterator,
    492 	   typename _BinaryOperation>
    493     inline _OutputIterator
    494     adjacent_difference(_IIter __begin, _IIter __end,
    495 			_OutputIterator __result, _BinaryOperation __binary_op)
    496     {
    497       typedef iterator_traits<_IIter> _ITraitsType;
    498       typedef typename _ITraitsType::iterator_category _IIteratorCategory;
    499 
    500       typedef iterator_traits<_OutputIterator> _OTraitsType;
    501       typedef typename _OTraitsType::iterator_category _OIterCategory;
    502 
    503       return __adjacent_difference_switch(__begin, __end, __result,
    504 					  __binary_op,
    505 					  _IIteratorCategory(),
    506 					  _OIterCategory());
    507     }
    508 } // end namespace
    509 } // end namespace
    510 
    511 #endif /* _GLIBCXX_NUMERIC_H */
    512