1 //=================================================================================================
2 /*!
3 //  \file blaze/math/expressions/SMatReduceExpr.h
4 //  \brief Header file for the sparse matrix reduce expression
5 //
6 //  Copyright (C) 2012-2020 Klaus Iglberger - All Rights Reserved
7 //
8 //  This file is part of the Blaze library. You can redistribute it and/or modify it under
9 //  the terms of the New (Revised) BSD License. Redistribution and use in source and binary
10 //  forms, with or without modification, are permitted provided that the following conditions
11 //  are met:
12 //
13 //  1. Redistributions of source code must retain the above copyright notice, this list of
14 //     conditions and the following disclaimer.
15 //  2. Redistributions in binary form must reproduce the above copyright notice, this list
16 //     of conditions and the following disclaimer in the documentation and/or other materials
17 //     provided with the distribution.
18 //  3. Neither the names of the Blaze development group nor the names of its contributors
19 //     may be used to endorse or promote products derived from this software without specific
20 //     prior written permission.
21 //
22 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23 //  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 //  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 //  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 //  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 //  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 //  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 //  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 //  DAMAGE.
32 */
33 //=================================================================================================
34 
35 #ifndef _BLAZE_MATH_EXPRESSIONS_SMATREDUCEEXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_SMATREDUCEEXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <iterator>
44 #include <blaze/math/Aliases.h>
45 #include <blaze/math/constraints/ColumnMajorMatrix.h>
46 #include <blaze/math/constraints/ColumnVector.h>
47 #include <blaze/math/constraints/DenseVector.h>
48 #include <blaze/math/constraints/RequiresEvaluation.h>
49 #include <blaze/math/constraints/RowMajorMatrix.h>
50 #include <blaze/math/constraints/RowVector.h>
51 #include <blaze/math/constraints/SparseMatrix.h>
52 #include <blaze/math/Exception.h>
53 #include <blaze/math/expressions/Computation.h>
54 #include <blaze/math/expressions/DenseVector.h>
55 #include <blaze/math/expressions/Forward.h>
56 #include <blaze/math/expressions/MatReduceExpr.h>
57 #include <blaze/math/expressions/SparseMatrix.h>
58 #include <blaze/math/functors/Add.h>
59 #include <blaze/math/functors/Max.h>
60 #include <blaze/math/functors/Min.h>
61 #include <blaze/math/functors/Mult.h>
62 #include <blaze/math/ReductionFlag.h>
63 #include <blaze/math/shims/Serial.h>
64 #include <blaze/math/traits/ReduceTrait.h>
65 #include <blaze/math/typetraits/IsExpression.h>
66 #include <blaze/math/typetraits/RequiresEvaluation.h>
67 #include <blaze/math/views/Check.h>
68 #include <blaze/system/MacroDisable.h>
69 #include <blaze/system/Thresholds.h>
70 #include <blaze/util/Assert.h>
71 #include <blaze/util/EnableIf.h>
72 #include <blaze/util/FunctionTrace.h>
73 #include <blaze/util/mpl/If.h>
74 #include <blaze/util/StaticAssert.h>
75 #include <blaze/util/Types.h>
76 #include <blaze/util/typetraits/HasMember.h>
77 
78 
79 namespace blaze {
80 
81 //=================================================================================================
82 //
83 //  CLASS DEFINITION
84 //
85 //=================================================================================================
86 
87 //*************************************************************************************************
88 /*!\brief Base template for row-major sparse matrix partial reduction operations.
89 // \ingroup dense_vector_expression
90 //
91 // The SMatReduceExpr class represents the compile time expression for partial reduction operations
92 // of row-major sparse matrices.
93 */
94 template< typename MT         // Type of the sparse matrix
95         , typename OP         // Type of the reduction operation
96         , ReductionFlag RF >  // Reduction flag
97 class SMatReduceExpr
98 {};
99 //*************************************************************************************************
100 
101 
102 
103 
104 //=================================================================================================
105 //
106 //  CLASS TEMPLATE SPECIALIZATION FOR COLUMN-WISE REDUCTION OPERATIONS OF ROW-MAJOR MATRICES
107 //
108 //=================================================================================================
109 
110 //*************************************************************************************************
111 /*!\brief Expression object for column-wise row-major sparse matrix reduction operations.
112 // \ingroup dense_vector_expression
113 //
114 // This specialization of the SMatReduceExpr class template represents the compile time expression
115 // for column-wise reduction operations of row-major sparse matrices.
116 */
117 template< typename MT    // Type of the sparse matrix
118         , typename OP >  // Type of the reduction operation
119 class SMatReduceExpr<MT,OP,columnwise>
120    : public MatReduceExpr< DenseVector< SMatReduceExpr<MT,OP,columnwise>, true >, columnwise >
121    , private Computation
122 {
123  private:
124    //**Type definitions****************************************************************************
125    using RT = ResultType_t<MT>;     //!< Result type of the sparse matrix expression.
126    using OT = OppositeType_t<MT>;   //!< Opposite type of the sparse matrix expression.
127    using ET = ElementType_t<MT>;    //!< Element type of the sparse matrix expression.
128    using CT = CompositeType_t<MT>;  //!< Composite type of the sparse matrix expression.
129    //**********************************************************************************************
130 
131    //**Parallel evaluation strategy****************************************************************
132    /*! \cond BLAZE_INTERNAL */
133    //! Helper variable template for the explicit application of the SFINAE principle.
134    /*! This variable template is a helper for the selection of the parallel evaluation strategy.
135        In case the sparse matrix operand is not SMP assignable and requires an intermediate
136        evaluation, the variable is set to 1 and the expression specific evaluation strategy is
137        selected. Otherwise the variable is set to 0 and the default strategy is chosen. */
138    template< typename VT >
139    static constexpr bool UseSMPAssign_v = ( !MT::smpAssignable && RequiresEvaluation_v<MT> );
140    /*! \endcond */
141    //**********************************************************************************************
142 
143  public:
144    //**Type definitions****************************************************************************
145    //! Type of this SMatReduceExpr instance.
146    using This = SMatReduceExpr<MT,OP,columnwise>;
147 
148    //! Base type of this SMatReduceExpr instance.
149    using BaseType = MatReduceExpr< DenseVector<This,true>, columnwise >;
150 
151    using ResultType    = ReduceTrait_t<RT,OP,columnwise>;  //!< Result type for expression template evaluations.
152    using TransposeType = TransposeType_t<ResultType>;      //!< Transpose type for expression template evaluations.
153    using ElementType   = ElementType_t<ResultType>;        //!< Resulting element type.
154    using SIMDType      = SIMDTrait_t<ElementType>;         //!< Resulting SIMD element type.
155    using ReturnType    = const ElementType;                //!< Return type for expression template evaluations.
156    using CompositeType = const ResultType;                 //!< Data type for composite expression templates.
157 
158    //! Composite type of the left-hand side sparse matrix expression.
159    using Operand = If_t< IsExpression_v<MT>, const MT, const MT& >;
160 
161    //! Data type of the custom unary operation.
162    using Operation = OP;
163    //**********************************************************************************************
164 
165    //**Compilation flags***************************************************************************
166    //! Compilation switch for the expression template evaluation strategy.
167    static constexpr bool simdEnabled = false;
168 
169    //! Compilation switch for the expression template assignment strategy.
170    static constexpr bool smpAssignable = MT::smpAssignable;
171    //**********************************************************************************************
172 
173    //**Constructor*********************************************************************************
174    /*!\brief Constructor for the SMatReduceExpr class.
175    //
176    // \param sm The matrix operand of the reduction expression.
177    // \param op The reduction operation.
178    */
SMatReduceExpr(const MT & sm,OP op)179    inline SMatReduceExpr( const MT& sm, OP op ) noexcept
180       : sm_( sm )             // Sparse matrix of the reduction expression
181       , op_( std::move(op) )  // The reduction operation
182    {}
183    //**********************************************************************************************
184 
185    //**Subscript operator**************************************************************************
186    /*!\brief Subscript operator for the direct access to the vector elements.
187    //
188    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
189    // \return The resulting value.
190    */
191    inline ReturnType operator[]( size_t index ) const {
192       BLAZE_INTERNAL_ASSERT( index < sm_.columns(), "Invalid vector access index" );
193       return reduce( column( sm_, index, unchecked ), op_ );
194    }
195    //**********************************************************************************************
196 
197    //**At function*********************************************************************************
198    /*!\brief Checked access to the vector elements.
199    //
200    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
201    // \return The resulting value.
202    // \exception std::out_of_range Invalid vector access index.
203    */
at(size_t index)204    inline ReturnType at( size_t index ) const {
205       if( index >= sm_.columns() ) {
206          BLAZE_THROW_OUT_OF_RANGE( "Invalid vector access index" );
207       }
208       return (*this)[index];
209    }
210    //**********************************************************************************************
211 
212    //**Size function*******************************************************************************
213    /*!\brief Returns the current size/dimension of the vector.
214    //
215    // \return The size of the vector.
216    */
size()217    inline size_t size() const noexcept {
218       return sm_.columns();
219    }
220    //**********************************************************************************************
221 
222    //**Operand access******************************************************************************
223    /*!\brief Returns the sparse matrix operand.
224    //
225    // \return The sparse matrix operand.
226    */
operand()227    inline Operand operand() const noexcept {
228       return sm_;
229    }
230    //**********************************************************************************************
231 
232    //**Operation access****************************************************************************
233    /*!\brief Returns a copy of the reduction operation.
234    //
235    // \return A copy of the reduction operation.
236    */
operation()237    inline Operation operation() const {
238       return op_;
239    }
240    //**********************************************************************************************
241 
242    //**********************************************************************************************
243    /*!\brief Returns whether the expression can alias with the given address \a alias.
244    //
245    // \param alias The alias to be checked.
246    // \return \a true in case an aliasing effect is possible, \a false if not.
247    */
248    template< typename T >
canAlias(const T * alias)249    inline bool canAlias( const T* alias ) const noexcept {
250       return ( sm_.isAliased( alias ) );
251    }
252    //**********************************************************************************************
253 
254    //**********************************************************************************************
255    /*!\brief Returns whether the expression is aliased with the given address \a alias.
256    //
257    // \param alias The alias to be checked.
258    // \return \a true in case the given alias is contained in this expression, \a false if not.
259    */
260    template< typename T >
isAliased(const T * alias)261    inline bool isAliased( const T* alias ) const noexcept {
262       return ( sm_.isAliased( alias ) );
263    }
264    //**********************************************************************************************
265 
266    //**********************************************************************************************
267    /*!\brief Returns whether the operands of the expression are properly aligned in memory.
268    //
269    // \return \a true in case the operands are aligned, \a false if not.
270    */
isAligned()271    inline bool isAligned() const noexcept {
272       return false;
273    }
274    //**********************************************************************************************
275 
276    //**********************************************************************************************
277    /*!\brief Returns whether the expression can be used in SMP assignments.
278    //
279    // \return \a true in case the expression can be used in SMP assignments, \a false if not.
280    */
canSMPAssign()281    inline bool canSMPAssign() const noexcept {
282       return sm_.canSMPAssign() || ( size() > SMP_SMATREDUCE_THRESHOLD );
283    }
284    //**********************************************************************************************
285 
286  private:
287    //**Member variables****************************************************************************
288    Operand   sm_;  //!< Sparse matrix of the reduction expression.
289    Operation op_;  //!< The reduction operation.
290    //**********************************************************************************************
291 
292    //**Assignment to dense vectors*****************************************************************
293    /*! \cond BLAZE_INTERNAL */
294    /*!\brief Assignment of a column-wise row-major sparse matrix reduction operation to a dense vector.
295    // \ingroup dense_vector
296    //
297    // \param lhs The target left-hand side dense vector.
298    // \param rhs The right-hand side reduction expression to be assigned.
299    // \return void
300    //
301    // This function implements the performance optimized assignment of a column-wise row-major
302    // sparse matrix reduction expression to a dense vector.
303    */
304    template< typename VT1 >  // Type of the target dense vector
assign(DenseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)305    friend inline void assign( DenseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
306    {
307       BLAZE_FUNCTION_TRACE;
308 
309       BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( OT );
310       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OT );
311       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( OT );
312 
313       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
314 
315       const OT tmp( serial( rhs.sm_ ) );
316       assign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
317    }
318    /*! \endcond */
319    //**********************************************************************************************
320 
321    //**Assignment to sparse vectors****************************************************************
322    /*! \cond BLAZE_INTERNAL */
323    /*!\brief Assignment of a column-wise row-major sparse matrix reduction operation to a dense
324    //        vector.
325    // \ingroup dense_vector
326    //
327    // \param lhs The target left-hand side dense vector.
328    // \param rhs The right-hand side reduction expression to be assigned.
329    // \return void
330    //
331    // This function implements the performance optimized assignment of a column-wise row-major
332    // sparse matrix reduction expression to a dense vector.
333    */
334    template< typename VT1 >  // Type of the target dense vector
assign(SparseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)335    friend inline void assign( SparseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
336    {
337       BLAZE_FUNCTION_TRACE;
338 
339       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
340       BLAZE_CONSTRAINT_MUST_BE_ROW_VECTOR_TYPE( ResultType );
341       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
342 
343       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
344 
345       const ResultType tmp( serial( rhs ) );
346       assign( *lhs, tmp );
347    }
348    /*! \endcond */
349    //**********************************************************************************************
350 
351    //**Addition assignment to dense vectors********************************************************
352    /*! \cond BLAZE_INTERNAL */
353    /*!\brief Addition assignment of a column-wise row-major sparse matrix reduction operation to a
354    //        dense vector.
355    // \ingroup dense_vector
356    //
357    // \param lhs The target left-hand side dense vector.
358    // \param rhs The right-hand side reduction expression to be added.
359    // \return void
360    //
361    // This function implements the performance optimized addition assignment of a column-wise
362    // row-major sparse matrix reduction expression to a dense vector.
363    */
364    template< typename VT1 >  // Type of the target dense vector
addAssign(DenseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)365    friend inline void addAssign( DenseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
366    {
367       BLAZE_FUNCTION_TRACE;
368 
369       BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( OT );
370       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OT );
371       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( OT );
372 
373       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
374 
375       const OT tmp( serial( rhs.sm_ ) );
376       addAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
377    }
378    /*! \endcond */
379    //**********************************************************************************************
380 
381    //**Addition assignment to sparse vectors*******************************************************
382    /*! \cond BLAZE_INTERNAL */
383    /*!\brief Addition assignment of a column-wise row-major sparse matrix reduction operation
384    //        to a dense vector.
385    // \ingroup dense_vector
386    //
387    // \param lhs The target left-hand side dense vector.
388    // \param rhs The right-hand side reduction expression to be added.
389    // \return void
390    //
391    // This function implements the performance optimized addition assignment of a column-wise
392    // row-major sparse matrix reduction expression to a dense vector.
393    */
394    template< typename VT1 >  // Type of the target dense vector
addAssign(SparseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)395    friend inline void addAssign( SparseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
396    {
397       BLAZE_FUNCTION_TRACE;
398 
399       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
400       BLAZE_CONSTRAINT_MUST_BE_ROW_VECTOR_TYPE( ResultType );
401       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
402 
403       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
404 
405       const ResultType tmp( serial( rhs ) );
406       addAssign( *lhs, tmp );
407    }
408    /*! \endcond */
409    //**********************************************************************************************
410 
411    //**Subtraction assignment to dense vectors*****************************************************
412    /*! \cond BLAZE_INTERNAL */
413    /*!\brief Subtraction assignment of a column-wise row-major sparse matrix reduction operation
414    //        to a dense vector.
415    // \ingroup dense_vector
416    //
417    // \param lhs The target left-hand side dense vector.
418    // \param rhs The right-hand side reduction expression to be subtracted.
419    // \return void
420    //
421    // This function implements the performance optimized subtraction assignment of a column-wise
422    // row-major sparse matrix reduction expression to a dense vector.
423    */
424    template< typename VT1 >  // Type of the target dense vector
subAssign(DenseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)425    friend inline void subAssign( DenseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
426    {
427       BLAZE_FUNCTION_TRACE;
428 
429       BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( OT );
430       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OT );
431       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( OT );
432 
433       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
434 
435       const OT tmp( serial( rhs.sm_ ) );
436       subAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
437    }
438    /*! \endcond */
439    //**********************************************************************************************
440 
441    //**Subtraction assignment to sparse vectors****************************************************
442    /*! \cond BLAZE_INTERNAL */
443    /*!\brief Subtraction assignment of a column-wise row-major sparse matrix reduction operation
444    //        to a dense vector.
445    // \ingroup dense_vector
446    //
447    // \param lhs The target left-hand side dense vector.
448    // \param rhs The right-hand side reduction expression to be subtracted.
449    // \return void
450    //
451    // This function implements the performance optimized subtraction assignment of a column-wise
452    // row-major sparse matrix reduction expression to a dense vector.
453    */
454    template< typename VT1 >  // Type of the target dense vector
subAssign(SparseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)455    friend inline void subAssign( SparseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
456    {
457       BLAZE_FUNCTION_TRACE;
458 
459       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
460       BLAZE_CONSTRAINT_MUST_BE_ROW_VECTOR_TYPE( ResultType );
461       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
462 
463       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
464 
465       const ResultType tmp( serial( rhs ) );
466       subAssign( *lhs, tmp );
467    }
468    /*! \endcond */
469    //**********************************************************************************************
470 
471    //**Multiplication assignment to dense vectors**************************************************
472    /*! \cond BLAZE_INTERNAL */
473    /*!\brief Multiplication assignment of a column-wise row-major sparse matrix reduction operation
474    //        to a dense vector.
475    // \ingroup dense_vector
476    //
477    // \param lhs The target left-hand side dense vector.
478    // \param rhs The right-hand side reduction expression to be multiplied.
479    // \return void
480    //
481    // This function implements the performance optimized multiplication assignment of a column-wise
482    // row-major sparse matrix reduction expression to a dense vector.
483    */
484    template< typename VT1 >  // Type of the target dense vector
multAssign(DenseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)485    friend inline void multAssign( DenseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
486    {
487       BLAZE_FUNCTION_TRACE;
488 
489       BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( OT );
490       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OT );
491       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( OT );
492 
493       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
494 
495       const OT tmp( serial( rhs.sm_ ) );
496       multAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
497    }
498    /*! \endcond */
499    //**********************************************************************************************
500 
501    //**Multiplication assignment to sparse vectors*************************************************
502    /*! \cond BLAZE_INTERNAL */
503    /*!\brief Multiplication assignment of a column-wise row-major sparse matrix reduction operation
504    //        to a dense vector.
505    // \ingroup dense_vector
506    //
507    // \param lhs The target left-hand side dense vector.
508    // \param rhs The right-hand side reduction expression to be multiplied.
509    // \return void
510    //
511    // This function implements the performance optimized multiplication assignment of a column-wise
512    // row-major sparse matrix reduction expression to a dense vector.
513    */
514    template< typename VT1 >  // Type of the target dense vector
multAssign(SparseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)515    friend inline void multAssign( SparseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
516    {
517       BLAZE_FUNCTION_TRACE;
518 
519       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
520       BLAZE_CONSTRAINT_MUST_BE_ROW_VECTOR_TYPE( ResultType );
521       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
522 
523       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
524 
525       const ResultType tmp( serial( rhs ) );
526       multAssign( *lhs, tmp );
527    }
528    /*! \endcond */
529    //**********************************************************************************************
530 
531    //**Division assignment to dense vectors********************************************************
532    /*! \cond BLAZE_INTERNAL */
533    /*!\brief Division assignment of a column-wise row-major sparse matrix reduction operation
534    //        to a dense vector.
535    // \ingroup dense_vector
536    //
537    // \param lhs The target left-hand side dense vector.
538    // \param rhs The right-hand side reduction expression divisor.
539    // \return void
540    //
541    // This function implements the performance optimized division assignment of a column-wise
542    // row-major sparse matrix reduction expression to a dense vector.
543    */
544    template< typename VT1 >  // Type of the target dense vector
divAssign(DenseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)545    friend inline void divAssign( DenseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
546    {
547       BLAZE_FUNCTION_TRACE;
548 
549       BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( OT );
550       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OT );
551       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( OT );
552 
553       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
554 
555       const OT tmp( serial( rhs.sm_ ) );
556       divAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
557    }
558    /*! \endcond */
559    //**********************************************************************************************
560 
561    //**Division assignment to sparse vectors*******************************************************
562    /*! \cond BLAZE_INTERNAL */
563    /*!\brief Division assignment of a column-wise row-major sparse matrix reduction operation
564    //        to a dense vector.
565    // \ingroup dense_vector
566    //
567    // \param lhs The target left-hand side dense vector.
568    // \param rhs The right-hand side reduction expression divisor.
569    // \return void
570    //
571    // This function implements the performance optimized division assignment of a column-wise
572    // row-major sparse matrix reduction expression to a dense vector.
573    */
574    template< typename VT1 >  // Type of the target dense vector
divAssign(SparseVector<VT1,true> & lhs,const SMatReduceExpr & rhs)575    friend inline void divAssign( SparseVector<VT1,true>& lhs, const SMatReduceExpr& rhs )
576    {
577       BLAZE_FUNCTION_TRACE;
578 
579       BLAZE_CONSTRAINT_MUST_BE_DENSE_VECTOR_TYPE( ResultType );
580       BLAZE_CONSTRAINT_MUST_BE_ROW_VECTOR_TYPE( ResultType );
581       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
582 
583       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
584 
585       const ResultType tmp( serial( rhs ) );
586       divAssign( *lhs, tmp );
587    }
588    /*! \endcond */
589    //**********************************************************************************************
590 
591    //**SMP assignment to vectors*******************************************************************
592    /*! \cond BLAZE_INTERNAL */
593    /*!\brief SMP assignment of a column-wise row-major sparse matrix reduction operation to a vector.
594    // \ingroup dense_vector
595    //
596    // \param lhs The target left-hand side vector.
597    // \param rhs The right-hand side reduction expression to be assigned.
598    // \return void
599    //
600    // This function implements the performance optimized SMP assignment of a column-wise row-major
601    // sparse matrix reduction expression to a vector. Due to the explicit application of the SFINAE
602    // principle, this function can only be selected by the compiler in case the expression specific
603    // parallel evaluation strategy is selected.
604    */
605    template< typename VT1 >  // Type of the target vector
606    friend inline auto smpAssign( Vector<VT1,true>& lhs, const SMatReduceExpr& rhs )
607       -> EnableIf_t< UseSMPAssign_v<VT1> >
608    {
609       BLAZE_FUNCTION_TRACE;
610 
611       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
612 
613       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
614       smpAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
615    }
616    /*! \endcond */
617    //**********************************************************************************************
618 
619    //**SMP addition assignment to vectors**********************************************************
620    /*! \cond BLAZE_INTERNAL */
621    /*!\brief SMP addition assignment of a column-wise row-major sparse matrix reduction operation
622    //        to a vector.
623    // \ingroup dense_vector
624    //
625    // \param lhs The target left-hand side vector.
626    // \param rhs The right-hand side reduction expression to be added.
627    // \return void
628    //
629    // This function implements the performance optimized SMP addition assignment of a column-wise
630    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
631    // of the SFINAE principle, this function can only be selected by the compiler in case the
632    // expression specific parallel evaluation strategy is selected.
633    */
634    template< typename VT1 >  // Type of the target vector
635    friend inline auto smpAddAssign( Vector<VT1,true>& lhs, const SMatReduceExpr& rhs )
636       -> EnableIf_t< UseSMPAssign_v<VT1> >
637    {
638       BLAZE_FUNCTION_TRACE;
639 
640       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
641 
642       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
643       smpAddAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
644    }
645    /*! \endcond */
646    //**********************************************************************************************
647 
648    //**SMP subtraction assignment to vectors*******************************************************
649    /*! \cond BLAZE_INTERNAL */
650    /*!\brief SMP subtraction assignment of a column-wise row-major sparse matrix reduction operation
651    //        to a vector.
652    // \ingroup dense_vector
653    //
654    // \param lhs The target left-hand side vector.
655    // \param rhs The right-hand side reduction expression to be subtracted.
656    // \return void
657    //
658    // This function implements the performance optimized SMP subtraction assignment of a column-wise
659    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
660    // of the SFINAE principle, this function can only be selected by the compiler in case the
661    // expression specific parallel evaluation strategy is selected.
662    */
663    template< typename VT1 >  // Type of the target vector
664    friend inline auto smpSubAssign( Vector<VT1,true>& lhs, const SMatReduceExpr& rhs )
665       -> EnableIf_t< UseSMPAssign_v<VT1> >
666    {
667       BLAZE_FUNCTION_TRACE;
668 
669       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
670 
671       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
672       smpSubAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
673    }
674    /*! \endcond */
675    //**********************************************************************************************
676 
677    //**SMP multiplication assignment to vectors****************************************************
678    /*! \cond BLAZE_INTERNAL */
679    /*!\brief SMP multiplication assignment of a column-wise row-major sparse matrix reduction
680    //        operation to a vector.
681    // \ingroup dense_vector
682    //
683    // \param lhs The target left-hand side vector.
684    // \param rhs The right-hand side reduction expression to be multiplied.
685    // \return void
686    //
687    // This function implements the performance optimized SMP multiplication assignment of a
688    // column-wise row-major sparse matrix reduction expression to a vector. Due to the explicit
689    // application of the SFINAE principle, this function can only be selected by the compiler
690    // in case the expression specific parallel evaluation strategy is selected.
691    */
692    template< typename VT1 >  // Type of the target vector
693    friend inline auto smpMultAssign( Vector<VT1,true>& lhs, const SMatReduceExpr& rhs )
694       -> EnableIf_t< UseSMPAssign_v<VT1> >
695    {
696       BLAZE_FUNCTION_TRACE;
697 
698       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
699 
700       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
701       smpMultAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
702    }
703    /*! \endcond */
704    //**********************************************************************************************
705 
706    //**SMP division assignment to vectors**********************************************************
707    /*! \cond BLAZE_INTERNAL */
708    /*!\brief SMP division assignment of a column-wise row-major sparse matrix reduction operation
709    //        to a vector.
710    // \ingroup dense_vector
711    //
712    // \param lhs The target left-hand side vector.
713    // \param rhs The right-hand side reduction expression divisor.
714    // \return void
715    //
716    // This function implements the performance optimized SMP division assignment of a column-wise
717    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
718    // of the SFINAE principle, this function can only be selected by the compiler in case the
719    // expression specific parallel evaluation strategy is selected.
720    */
721    template< typename VT1 >  // Type of the target vector
722    friend inline auto smpDivAssign( Vector<VT1,true>& lhs, const SMatReduceExpr& rhs )
723       -> EnableIf_t< UseSMPAssign_v<VT1> >
724    {
725       BLAZE_FUNCTION_TRACE;
726 
727       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
728 
729       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
730       smpDivAssign( *lhs, reduce<columnwise>( tmp, rhs.op_ ) );
731    }
732    /*! \endcond */
733    //**********************************************************************************************
734 
735    //**Compile time checks*************************************************************************
736    /*! \cond BLAZE_INTERNAL */
737    BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( MT );
738    BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( MT );
739    /*! \endcond */
740    //**********************************************************************************************
741 };
742 //*************************************************************************************************
743 
744 
745 
746 
747 //=================================================================================================
748 //
749 //  CLASS TEMPLATE SPECIALIZATION FOR ROW-WISE REDUCTION OPERATIONS OF ROW-MAJOR MATRICES
750 //
751 //=================================================================================================
752 
753 //*************************************************************************************************
754 /*!\brief Expression object for row-wise row-major sparse matrix reduction operations.
755 // \ingroup dense_vector_expression
756 //
757 // This specialization of the SMatReduceExpr class template represents the compile time expression
758 // for row-wise reduction operations of row-major sparse matrices.
759 */
760 template< typename MT    // Type of the sparse matrix
761         , typename OP >  // Type of the reduction operation
762 class SMatReduceExpr<MT,OP,rowwise>
763    : public MatReduceExpr< DenseVector< SMatReduceExpr<MT,OP,rowwise>, false >, rowwise >
764    , private Computation
765 {
766  private:
767    //**Type definitions****************************************************************************
768    using RT = ResultType_t<MT>;   //!< Result type of the sparse matrix expression.
769    using ET = ElementType_t<MT>;  //!< Element type of the sparse matrix expression.
770    //**********************************************************************************************
771 
772    //**Serial evaluation strategy******************************************************************
773    //! Compilation switch for the serial evaluation strategy of the reduction expression.
774    /*! The \a useAssign compile time constant expression represents a compilation switch for
775        the serial evaluation strategy of the reduction expression. In case the sparse matrix
776        operand requires an intermediate evaluation, \a useAssign will be set to 1 and the
777        reduction expression will be evaluated via the \a assign function family. Otherwise
778        \a useAssign will be set to 0 and the expression will be evaluated via the subscript
779        operator. */
780    static constexpr bool useAssign = RequiresEvaluation_v<MT>;
781 
782    /*! \cond BLAZE_INTERNAL */
783    //! Helper variable template for the explicit application of the SFINAE principle.
784    template< typename VT >
785    static constexpr bool UseAssign_v = useAssign;
786    /*! \endcond */
787    //**********************************************************************************************
788 
789    //**Parallel evaluation strategy****************************************************************
790    /*! \cond BLAZE_INTERNAL */
791    //! Helper variable template for the explicit application of the SFINAE principle.
792    /*! This variable template is a helper for the selection of the parallel evaluation strategy.
793        In case the sparse matrix operand is not SMP assignable and requires an intermediate
794        evaluation, the variable is set to 1 and the expression specific evaluation strategy is
795        selected. Otherwise the variable is set to 0 and the default strategy is chosen. */
796    template< typename VT >
797    static constexpr bool UseSMPAssign_v = ( !MT::smpAssignable && useAssign );
798    /*! \endcond */
799    //**********************************************************************************************
800 
801  public:
802    //**Type definitions****************************************************************************
803    //! Type of this SMatReduceExpr instance.
804    using This = SMatReduceExpr<MT,OP,rowwise>;
805 
806    //! Base type of this SMatReduceExpr instance.
807    using BaseType = MatReduceExpr< DenseVector<This,false>, rowwise >;
808 
809    using ResultType    = ReduceTrait_t<RT,OP,rowwise>;  //!< Result type for expression template evaluations.
810    using TransposeType = TransposeType_t<ResultType>;   //!< Transpose type for expression template evaluations.
811    using ElementType   = ElementType_t<ResultType>;     //!< Resulting element type.
812    using SIMDType      = SIMDTrait_t<ElementType>;      //!< Resulting SIMD element type.
813    using ReturnType    = const ElementType;             //!< Return type for expression template evaluations.
814 
815    //! Data type for composite expression templates.
816    using CompositeType = If_t< useAssign, const ResultType, const SMatReduceExpr& >;
817 
818    //! Composite type of the left-hand side sparse matrix expression.
819    using Operand = If_t< IsExpression_v<MT>, const MT, const MT& >;
820 
821    //! Data type of the custom unary operation.
822    using Operation = OP;
823    //**********************************************************************************************
824 
825    //**ConstIterator class definition**************************************************************
826    /*!\brief Iterator over the elements of the dense vector.
827    */
828    class ConstIterator
829    {
830     public:
831       //**Type definitions*************************************************************************
832       using IteratorCategory = std::random_access_iterator_tag;  //!< The iterator category.
833       using ValueType        = ElementType;                      //!< Type of the underlying elements.
834       using PointerType      = ElementType*;                     //!< Pointer return type.
835       using ReferenceType    = ElementType&;                     //!< Reference return type.
836       using DifferenceType   = ptrdiff_t;                        //!< Difference between two iterators.
837 
838       // STL iterator requirements
839       using iterator_category = IteratorCategory;  //!< The iterator category.
840       using value_type        = ValueType;         //!< Type of the underlying elements.
841       using pointer           = PointerType;       //!< Pointer return type.
842       using reference         = ReferenceType;     //!< Reference return type.
843       using difference_type   = DifferenceType;    //!< Difference between two iterators.
844       //*******************************************************************************************
845 
846       //**Constructor******************************************************************************
847       /*!\brief Constructor for the ConstIterator class.
848       //
849       // \param sm The sparse matrix operand of the reduction expression.
850       // \param index Index to the initial matrix row.
851       // \param op The reduction operation.
852       */
ConstIterator(Operand sm,size_t index,OP op)853       inline ConstIterator( Operand sm, size_t index, OP op )
854          : sm_   ( sm )             // Sparse matrix of the reduction expression
855          , index_( index )          // Index to the current matrix row
856          , op_   ( std::move(op) )  // The reduction operation
857       {}
858       //*******************************************************************************************
859 
860       //**Addition assignment operator*************************************************************
861       /*!\brief Addition assignment operator.
862       //
863       // \param inc The increment of the iterator.
864       // \return The incremented iterator.
865       */
866       inline ConstIterator& operator+=( size_t inc ) {
867          index_ += inc;
868          return *this;
869       }
870       //*******************************************************************************************
871 
872       //**Subtraction assignment operator**********************************************************
873       /*!\brief Subtraction assignment operator.
874       //
875       // \param dec The decrement of the iterator.
876       // \return The decremented iterator.
877       */
878       inline ConstIterator& operator-=( size_t dec ) {
879          index_ -= dec;
880          return *this;
881       }
882       //*******************************************************************************************
883 
884       //**Prefix increment operator****************************************************************
885       /*!\brief Pre-increment operator.
886       //
887       // \return Reference to the incremented iterator.
888       */
889       inline ConstIterator& operator++() {
890          ++index_;
891          return *this;
892       }
893       //*******************************************************************************************
894 
895       //**Postfix increment operator***************************************************************
896       /*!\brief Post-increment operator.
897       //
898       // \return The previous position of the iterator.
899       */
900       inline const ConstIterator operator++( int ) {
901          return ConstIterator( index_++ );
902       }
903       //*******************************************************************************************
904 
905       //**Prefix decrement operator****************************************************************
906       /*!\brief Pre-decrement operator.
907       //
908       // \return Reference to the decremented iterator.
909       */
910       inline ConstIterator& operator--() {
911          --index_;
912          return *this;
913       }
914       //*******************************************************************************************
915 
916       //**Postfix decrement operator***************************************************************
917       /*!\brief Post-decrement operator.
918       //
919       // \return The previous position of the iterator.
920       */
921       inline const ConstIterator operator--( int ) {
922          return ConstIterator( index_-- );
923       }
924       //*******************************************************************************************
925 
926       //**Element access operator******************************************************************
927       /*!\brief Direct access to the element at the current iterator position.
928       //
929       // \return The resulting value.
930       */
931       inline ReturnType operator*() const {
932          return reduce( row( sm_, index_, unchecked ), op_ );
933       }
934       //*******************************************************************************************
935 
936       //**Equality operator************************************************************************
937       /*!\brief Equality comparison between two ConstIterator objects.
938       //
939       // \param rhs The right-hand side iterator.
940       // \return \a true if the iterators refer to the same element, \a false if not.
941       */
942       inline bool operator==( const ConstIterator& rhs ) const {
943          return index_ == rhs.index_;
944       }
945       //*******************************************************************************************
946 
947       //**Inequality operator**********************************************************************
948       /*!\brief Inequality comparison between two ConstIterator objects.
949       //
950       // \param rhs The right-hand side iterator.
951       // \return \a true if the iterators don't refer to the same element, \a false if they do.
952       */
953       inline bool operator!=( const ConstIterator& rhs ) const {
954          return index_ != rhs.index_;
955       }
956       //*******************************************************************************************
957 
958       //**Less-than operator***********************************************************************
959       /*!\brief Less-than comparison between two ConstIterator objects.
960       //
961       // \param rhs The right-hand side iterator.
962       // \return \a true if the left-hand side iterator is smaller, \a false if not.
963       */
964       inline bool operator<( const ConstIterator& rhs ) const {
965          return index_ < rhs.index_;
966       }
967       //*******************************************************************************************
968 
969       //**Greater-than operator********************************************************************
970       /*!\brief Greater-than comparison between two ConstIterator objects.
971       //
972       // \param rhs The right-hand side iterator.
973       // \return \a true if the left-hand side iterator is greater, \a false if not.
974       */
975       inline bool operator>( const ConstIterator& rhs ) const {
976          return index_ > rhs.index_;
977       }
978       //*******************************************************************************************
979 
980       //**Less-or-equal-than operator**************************************************************
981       /*!\brief Less-than comparison between two ConstIterator objects.
982       //
983       // \param rhs The right-hand side iterator.
984       // \return \a true if the left-hand side iterator is smaller or equal, \a false if not.
985       */
986       inline bool operator<=( const ConstIterator& rhs ) const {
987          return index_ <= rhs.index_;
988       }
989       //*******************************************************************************************
990 
991       //**Greater-or-equal-than operator***********************************************************
992       /*!\brief Greater-than comparison between two ConstIterator objects.
993       //
994       // \param rhs The right-hand side iterator.
995       // \return \a true if the left-hand side iterator is greater or equal, \a false if not.
996       */
997       inline bool operator>=( const ConstIterator& rhs ) const {
998          return index_ >= rhs.index_;
999       }
1000       //*******************************************************************************************
1001 
1002       //**Subtraction operator*********************************************************************
1003       /*!\brief Calculating the number of elements between two iterators.
1004       //
1005       // \param rhs The right-hand side iterator.
1006       // \return The number of elements between the two iterators.
1007       */
1008       inline DifferenceType operator-( const ConstIterator& rhs ) const {
1009          return index_ - rhs.index_;
1010       }
1011       //*******************************************************************************************
1012 
1013       //**Addition operator************************************************************************
1014       /*!\brief Addition between a ConstIterator and an integral value.
1015       //
1016       // \param it The iterator to be incremented.
1017       // \param inc The number of elements the iterator is incremented.
1018       // \return The incremented iterator.
1019       */
1020       friend inline const ConstIterator operator+( const ConstIterator& it, size_t inc ) {
1021          return ConstIterator( it.index_ + inc );
1022       }
1023       //*******************************************************************************************
1024 
1025       //**Addition operator************************************************************************
1026       /*!\brief Addition between an integral value and a ConstIterator.
1027       //
1028       // \param inc The number of elements the iterator is incremented.
1029       // \param it The iterator to be incremented.
1030       // \return The incremented iterator.
1031       */
1032       friend inline const ConstIterator operator+( size_t inc, const ConstIterator& it ) {
1033          return ConstIterator( it.index_ + inc );
1034       }
1035       //*******************************************************************************************
1036 
1037       //**Subtraction operator*********************************************************************
1038       /*!\brief Subtraction between a ConstIterator and an integral value.
1039       //
1040       // \param it The iterator to be decremented.
1041       // \param dec The number of elements the iterator is decremented.
1042       // \return The decremented iterator.
1043       */
1044       friend inline const ConstIterator operator-( const ConstIterator& it, size_t dec ) {
1045          return ConstIterator( it.index_ - dec );
1046       }
1047       //*******************************************************************************************
1048 
1049     private:
1050       //**Member variables*************************************************************************
1051       Operand sm_;     //!< Sparse matrix of the reduction expression.
1052       size_t  index_;  //!< Index to the current matrix row.
1053       OP      op_;     //!< The reduction operation.
1054       //*******************************************************************************************
1055    };
1056    //**********************************************************************************************
1057 
1058    //**Compilation flags***************************************************************************
1059    //! Compilation switch for the expression template evaluation strategy.
1060    static constexpr bool simdEnabled = false;
1061 
1062    //! Compilation switch for the expression template assignment strategy.
1063    static constexpr bool smpAssignable = MT::smpAssignable;
1064    //**********************************************************************************************
1065 
1066    //**Constructor*********************************************************************************
1067    /*!\brief Constructor for the SMatReduceExpr class.
1068    //
1069    // \param sm The matrix operand of the reduction expression.
1070    // \param op The reduction operation.
1071    */
SMatReduceExpr(const MT & sm,OP op)1072    inline SMatReduceExpr( const MT& sm, OP op ) noexcept
1073       : sm_( sm )             // Sparse matrix of the reduction expression
1074       , op_( std::move(op) )  // The reduction operation
1075    {}
1076    //**********************************************************************************************
1077 
1078    //**Subscript operator**************************************************************************
1079    /*!\brief Subscript operator for the direct access to the vector elements.
1080    //
1081    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
1082    // \return The resulting value.
1083    */
1084    inline ReturnType operator[]( size_t index ) const {
1085       BLAZE_INTERNAL_ASSERT( index < sm_.rows(), "Invalid vector access index" );
1086       return reduce( row( sm_, index, unchecked ), op_ );
1087    }
1088    //**********************************************************************************************
1089 
1090    //**At function*********************************************************************************
1091    /*!\brief Checked access to the vector elements.
1092    //
1093    // \param index Access index. The index has to be in the range \f$[0..N-1]\f$.
1094    // \return The resulting value.
1095    // \exception std::out_of_range Invalid vector access index.
1096    */
at(size_t index)1097    inline ReturnType at( size_t index ) const {
1098       if( index >= sm_.rows() ) {
1099          BLAZE_THROW_OUT_OF_RANGE( "Invalid vector access index" );
1100       }
1101       return (*this)[index];
1102    }
1103    //**********************************************************************************************
1104 
1105    //**Begin function******************************************************************************
1106    /*!\brief Returns an iterator to the first non-zero element of the dense vector.
1107    //
1108    // \return Iterator to the first non-zero element of the dense vector.
1109    */
begin()1110    inline ConstIterator begin() const {
1111       return ConstIterator( sm_, 0UL, op_ );
1112    }
1113    //**********************************************************************************************
1114 
1115    //**End function********************************************************************************
1116    /*!\brief Returns an iterator just past the last non-zero element of the dense vector.
1117    //
1118    // \return Iterator just past the last non-zero element of the dense vector.
1119    */
end()1120    inline ConstIterator end() const {
1121       return ConstIterator( sm_, size(), op_ );
1122    }
1123    //**********************************************************************************************
1124 
1125    //**Size function*******************************************************************************
1126    /*!\brief Returns the current size/dimension of the vector.
1127    //
1128    // \return The size of the vector.
1129    */
size()1130    inline size_t size() const noexcept {
1131       return sm_.rows();
1132    }
1133    //**********************************************************************************************
1134 
1135    //**Operand access******************************************************************************
1136    /*!\brief Returns the sparse matrix operand.
1137    //
1138    // \return The sparse matrix operand.
1139    */
operand()1140    inline Operand operand() const noexcept {
1141       return sm_;
1142    }
1143    //**********************************************************************************************
1144 
1145    //**Operation access****************************************************************************
1146    /*!\brief Returns a copy of the reduction operation.
1147    //
1148    // \return A copy of the reduction operation.
1149    */
operation()1150    inline Operation operation() const {
1151       return op_;
1152    }
1153    //**********************************************************************************************
1154 
1155    //**********************************************************************************************
1156    /*!\brief Returns whether the expression can alias with the given address \a alias.
1157    //
1158    // \param alias The alias to be checked.
1159    // \return \a true in case an aliasing effect is possible, \a false if not.
1160    */
1161    template< typename T >
canAlias(const T * alias)1162    inline bool canAlias( const T* alias ) const noexcept {
1163       return ( sm_.isAliased( alias ) );
1164    }
1165    //**********************************************************************************************
1166 
1167    //**********************************************************************************************
1168    /*!\brief Returns whether the expression is aliased with the given address \a alias.
1169    //
1170    // \param alias The alias to be checked.
1171    // \return \a true in case the given alias is contained in this expression, \a false if not.
1172    */
1173    template< typename T >
isAliased(const T * alias)1174    inline bool isAliased( const T* alias ) const noexcept {
1175       return ( sm_.isAliased( alias ) );
1176    }
1177    //**********************************************************************************************
1178 
1179    //**********************************************************************************************
1180    /*!\brief Returns whether the operands of the expression are properly aligned in memory.
1181    //
1182    // \return \a true in case the operands are aligned, \a false if not.
1183    */
isAligned()1184    inline bool isAligned() const noexcept {
1185       return false;
1186    }
1187    //**********************************************************************************************
1188 
1189    //**********************************************************************************************
1190    /*!\brief Returns whether the expression can be used in SMP assignments.
1191    //
1192    // \return \a true in case the expression can be used in SMP assignments, \a false if not.
1193    */
canSMPAssign()1194    inline bool canSMPAssign() const noexcept {
1195       return sm_.canSMPAssign() || ( size() > SMP_SMATREDUCE_THRESHOLD );
1196    }
1197    //**********************************************************************************************
1198 
1199  private:
1200    //**Member variables****************************************************************************
1201    Operand   sm_;  //!< Sparse matrix of the reduction expression.
1202    Operation op_;  //!< The reduction operation.
1203    //**********************************************************************************************
1204 
1205    //**Assignment to vectors***********************************************************************
1206    /*! \cond BLAZE_INTERNAL */
1207    /*!\brief Assignment of a row-wise row-major sparse matrix reduction operation to a vector.
1208    // \ingroup dense_vector
1209    //
1210    // \param lhs The target left-hand side vector.
1211    // \param rhs The right-hand side reduction expression to be assigned.
1212    // \return void
1213    //
1214    // This function implements the performance optimized assignment of a row-wise row-major
1215    // sparse matrix reduction expression to a vector. Due to the explicit application of the
1216    // SFINAE principle, this function can only be selected by the compiler in case the expression
1217    // specific parallel evaluation strategy is selected.
1218    */
1219    template< typename VT1 >  // Type of the target vector
1220    friend inline auto assign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1221       -> EnableIf_t< UseAssign_v<VT1> >
1222    {
1223       BLAZE_FUNCTION_TRACE;
1224 
1225       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1226 
1227       const RT tmp( serial( rhs.sm_ ) );  // Evaluation of the sparse matrix operand
1228       assign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1229    }
1230    /*! \endcond */
1231    //**********************************************************************************************
1232 
1233    //**Addition assignment to vectors**************************************************************
1234    /*! \cond BLAZE_INTERNAL */
1235    /*!\brief Addition assignment of a row-wise row-major sparse matrix reduction operation to a vector.
1236    // \ingroup dense_vector
1237    //
1238    // \param lhs The target left-hand side vector.
1239    // \param rhs The right-hand side reduction expression to be added.
1240    // \return void
1241    //
1242    // This function implements the performance optimized addition assignment of a row-wise
1243    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1244    // of the SFINAE principle, this function can only be selected by the compiler in case the
1245    // expression specific parallel evaluation strategy is selected.
1246    */
1247    template< typename VT1 >  // Type of the target vector
1248    friend inline auto addAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1249       -> EnableIf_t< UseAssign_v<VT1> >
1250    {
1251       BLAZE_FUNCTION_TRACE;
1252 
1253       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1254 
1255       const RT tmp( serial( rhs.sm_ ) );  // Evaluation of the sparse matrix operand
1256       addAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1257    }
1258    /*! \endcond */
1259    //**********************************************************************************************
1260 
1261    //**Subtraction assignment to vectors***********************************************************
1262    /*! \cond BLAZE_INTERNAL */
1263    /*!\brief Subtraction assignment of a row-wise row-major sparse matrix reduction operation
1264    //        to a vector.
1265    // \ingroup dense_vector
1266    //
1267    // \param lhs The target left-hand side vector.
1268    // \param rhs The right-hand side reduction expression to be subtracted.
1269    // \return void
1270    //
1271    // This function implements the performance optimized subtraction assignment of a row-wise
1272    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1273    // of the SFINAE principle, this function can only be selected by the compiler in case the
1274    // expression specific parallel evaluation strategy is selected.
1275    */
1276    template< typename VT1 >  // Type of the target vector
1277    friend inline auto subAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1278       -> EnableIf_t< UseAssign_v<VT1> >
1279    {
1280       BLAZE_FUNCTION_TRACE;
1281 
1282       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1283 
1284       const RT tmp( serial( rhs.sm_ ) );  // Evaluation of the sparse matrix operand
1285       subAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1286    }
1287    /*! \endcond */
1288    //**********************************************************************************************
1289 
1290    //**Multiplication assignment to vectors********************************************************
1291    /*! \cond BLAZE_INTERNAL */
1292    /*!\brief Multiplication assignment of a row-wise row-major sparse matrix reduction operation
1293    //        to a vector.
1294    // \ingroup dense_vector
1295    //
1296    // \param lhs The target left-hand side vector.
1297    // \param rhs The right-hand side reduction expression to be multiplied.
1298    // \return void
1299    //
1300    // This function implements the performance optimized multiplication assignment of a row-wise
1301    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1302    // of the SFINAE principle, this function can only be selected by the compiler in case the
1303    // expression specific parallel evaluation strategy is selected.
1304    */
1305    template< typename VT1 >  // Type of the target vector
1306    friend inline auto multAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1307       -> EnableIf_t< UseAssign_v<VT1> >
1308    {
1309       BLAZE_FUNCTION_TRACE;
1310 
1311       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1312 
1313       const RT tmp( serial( rhs.sm_ ) );  // Evaluation of the sparse matrix operand
1314       multAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1315    }
1316    /*! \endcond */
1317    //**********************************************************************************************
1318 
1319    //**Division assignment to vectors**************************************************************
1320    /*! \cond BLAZE_INTERNAL */
1321    /*!\brief Division assignment of a row-wise row-major sparse matrix reduction operation to a vector.
1322    // \ingroup dense_vector
1323    //
1324    // \param lhs The target left-hand side vector.
1325    // \param rhs The right-hand side reduction expression divisor.
1326    // \return void
1327    //
1328    // This function implements the performance optimized division assignment of a row-wise
1329    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1330    // of the SFINAE principle, this function can only be selected by the compiler in case the
1331    // expression specific parallel evaluation strategy is selected.
1332    */
1333    template< typename VT1 >  // Type of the target vector
1334    friend inline auto divAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1335       -> EnableIf_t< UseAssign_v<VT1> >
1336    {
1337       BLAZE_FUNCTION_TRACE;
1338 
1339       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1340 
1341       const RT tmp( serial( rhs.sm_ ) );  // Evaluation of the sparse matrix operand
1342       divAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1343    }
1344    /*! \endcond */
1345    //**********************************************************************************************
1346 
1347    //**SMP assignment to vectors*******************************************************************
1348    /*! \cond BLAZE_INTERNAL */
1349    /*!\brief SMP assignment of a row-wise row-major sparse matrix reduction operation to a vector.
1350    // \ingroup dense_vector
1351    //
1352    // \param lhs The target left-hand side vector.
1353    // \param rhs The right-hand side reduction expression to be assigned.
1354    // \return void
1355    //
1356    // This function implements the performance optimized SMP assignment of a row-wise row-major
1357    // sparse matrix reduction expression to a vector. Due to the explicit application of the
1358    // SFINAE principle, this function can only be selected by the compiler in case the expression
1359    // specific parallel evaluation strategy is selected.
1360    */
1361    template< typename VT1 >  // Type of the target vector
1362    friend inline auto smpAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1363       -> EnableIf_t< UseSMPAssign_v<VT1> >
1364    {
1365       BLAZE_FUNCTION_TRACE;
1366 
1367       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1368 
1369       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
1370       smpAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1371    }
1372    /*! \endcond */
1373    //**********************************************************************************************
1374 
1375    //**SMP addition assignment to vectors**********************************************************
1376    /*! \cond BLAZE_INTERNAL */
1377    /*!\brief SMP addition assignment of a row-wise row-major sparse matrix reduction operation
1378    //        to a vector.
1379    // \ingroup dense_vector
1380    //
1381    // \param lhs The target left-hand side vector.
1382    // \param rhs The right-hand side reduction expression to be added.
1383    // \return void
1384    //
1385    // This function implements the performance optimized SMP addition assignment of a row-wise
1386    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1387    // of the SFINAE principle, this function can only be selected by the compiler in case the
1388    // expression specific parallel evaluation strategy is selected.
1389    */
1390    template< typename VT1 >  // Type of the target vector
1391    friend inline auto smpAddAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1392       -> EnableIf_t< UseSMPAssign_v<VT1> >
1393    {
1394       BLAZE_FUNCTION_TRACE;
1395 
1396       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1397 
1398       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
1399       smpAddAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1400    }
1401    /*! \endcond */
1402    //**********************************************************************************************
1403 
1404    //**SMP subtraction assignment to vectors*******************************************************
1405    /*! \cond BLAZE_INTERNAL */
1406    /*!\brief SMP subtraction assignment of a row-wise row-major sparse matrix reduction operation
1407    //        to a vector.
1408    // \ingroup dense_vector
1409    //
1410    // \param lhs The target left-hand side vector.
1411    // \param rhs The right-hand side reduction expression to be subtracted.
1412    // \return void
1413    //
1414    // This function implements the performance optimized SMP subtraction assignment of a row-wise
1415    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1416    // of the SFINAE principle, this function can only be selected by the compiler in case the
1417    // expression specific parallel evaluation strategy is selected.
1418    */
1419    template< typename VT1 >  // Type of the target vector
1420    friend inline auto smpSubAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1421       -> EnableIf_t< UseSMPAssign_v<VT1> >
1422    {
1423       BLAZE_FUNCTION_TRACE;
1424 
1425       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1426 
1427       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
1428       smpSubAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1429    }
1430    /*! \endcond */
1431    //**********************************************************************************************
1432 
1433    //**SMP multiplication assignment to vectors****************************************************
1434    /*! \cond BLAZE_INTERNAL */
1435    /*!\brief SMP multiplication assignment of a row-wise row-major sparse matrix reduction operation
1436    //        to a vector.
1437    // \ingroup dense_vector
1438    //
1439    // \param lhs The target left-hand side vector.
1440    // \param rhs The right-hand side reduction expression to be multiplied.
1441    // \return void
1442    //
1443    // This function implements the performance optimized SMP multiplication assignment of a
1444    // row-wise row-major sparse matrix reduction expression to a vector. Due to the explicit
1445    // application of the SFINAE principle, this function can only be selected by the compiler
1446    // in case the expression specific parallel evaluation strategy is selected.
1447    */
1448    template< typename VT1 >  // Type of the target vector
1449    friend inline auto smpMultAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1450       -> EnableIf_t< UseSMPAssign_v<VT1> >
1451    {
1452       BLAZE_FUNCTION_TRACE;
1453 
1454       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1455 
1456       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
1457       smpMultAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1458    }
1459    /*! \endcond */
1460    //**********************************************************************************************
1461 
1462    //**SMP division assignment to vectors**********************************************************
1463    /*! \cond BLAZE_INTERNAL */
1464    /*!\brief SMP division assignment of a row-wise row-major sparse matrix reduction operation
1465    //        to a vector.
1466    // \ingroup dense_vector
1467    //
1468    // \param lhs The target left-hand side vector.
1469    // \param rhs The right-hand side reduction expression divisor.
1470    // \return void
1471    //
1472    // This function implements the performance optimized SMP division assignment of a row-wise
1473    // row-major sparse matrix reduction expression to a vector. Due to the explicit application
1474    // of the SFINAE principle, this function can only be selected by the compiler in case the
1475    // expression specific parallel evaluation strategy is selected.
1476    */
1477    template< typename VT1 >  // Type of the target vector
1478    friend inline auto smpDivAssign( Vector<VT1,false>& lhs, const SMatReduceExpr& rhs )
1479       -> EnableIf_t< UseSMPAssign_v<VT1> >
1480    {
1481       BLAZE_FUNCTION_TRACE;
1482 
1483       BLAZE_INTERNAL_ASSERT( (*lhs).size() == rhs.size(), "Invalid vector sizes" );
1484 
1485       const RT tmp( rhs.sm_ );  // Evaluation of the sparse matrix operand
1486       smpDivAssign( *lhs, reduce<rowwise>( tmp, rhs.op_ ) );
1487    }
1488    /*! \endcond */
1489    //**********************************************************************************************
1490 
1491    //**Compile time checks*************************************************************************
1492    /*! \cond BLAZE_INTERNAL */
1493    BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( MT );
1494    BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( MT );
1495    /*! \endcond */
1496    //**********************************************************************************************
1497 };
1498 //*************************************************************************************************
1499 
1500 
1501 
1502 
1503 //=================================================================================================
1504 //
1505 //  GLOBAL FUNCTIONS
1506 //
1507 //=================================================================================================
1508 
1509 //*************************************************************************************************
1510 /*!\brief Performs a custom reduction operation on the given sparse matrix.
1511 // \ingroup sparse_matrix
1512 //
1513 // \param sm The given sparse matrix for the reduction computation.
1514 // \param op The reduction operation.
1515 // \return The result of the reduction operation.
1516 //
1517 // This function reduces the non-zero elements of the given sparse matrix \a sm by means of the
1518 // given reduction operation \a op:
1519 
1520    \code
1521    blaze::CompressedMatrix<double> A;
1522    // ... Resizing and initialization
1523 
1524    const double totalsum1 = reduce( A, blaze::Add() );
1525    const double totalsum2 = reduce( A, []( double a, double b ){ return a + b; } );
1526    \endcode
1527 
1528 // As demonstrated in the example it is possible to pass any binary callable as custom reduction
1529 // operation. See \ref custom_operations for a detailed overview of the possibilities of custom
1530 // operations.
1531 
1532 // Please note that the evaluation order of the reduction operation is unspecified. Thus the
1533 // behavior is non-deterministic if \a op is not associative or not commutative. Also, the
1534 // operation is undefined if the given reduction operation modifies the values.
1535 */
1536 template< typename MT    // Type of the sparse matrix
1537         , bool SO        // Storage order
1538         , typename OP >  // Type of the reduction operation
decltype(auto)1539 inline decltype(auto) reduce( const SparseMatrix<MT,SO>& sm, OP op )
1540 {
1541    BLAZE_FUNCTION_TRACE;
1542 
1543    using CT = CompositeType_t<MT>;
1544    using ET = ElementType_t<MT>;
1545 
1546    const size_t M( (*sm).rows()    );
1547    const size_t N( (*sm).columns() );
1548 
1549    if( M == 0UL || N == 0UL ) return ET{};
1550 
1551    const size_t iend( SO ? N : M );
1552 
1553    CT tmp( *sm );
1554 
1555    BLAZE_INTERNAL_ASSERT( tmp.rows()    == M, "Invalid number of rows"    );
1556    BLAZE_INTERNAL_ASSERT( tmp.columns() == N, "Invalid number of columns" );
1557 
1558    ET redux0{};
1559 
1560    for( size_t i=0UL; i<iend; ++i )
1561    {
1562       const auto end( tmp.end(i) );
1563       auto element( tmp.begin(i) );
1564 
1565       if( element == end ) continue;
1566 
1567       ET redux1( element->value() );
1568       ++element;
1569 
1570       for( ; element!=end; ++element ) {
1571          redux1 = op( redux1, element->value() );
1572       }
1573 
1574       if( i == 0UL ) redux0 = redux1;
1575       else           redux0 = op( redux0, redux1 );
1576    }
1577 
1578    return redux0;
1579 }
1580 //*************************************************************************************************
1581 
1582 
1583 //*************************************************************************************************
1584 /*! \cond BLAZE_INTERNAL */
1585 /*!\brief Backend implementation for custom reduction operations on row-major sparse matrices.
1586 // \ingroup sparse_matrix
1587 //
1588 // \param sm The given row-major sparse matrix for the reduction computation.
1589 // \param op The reduction operation.
1590 // \return The result of the reduction operation.
1591 */
1592 template< ReductionFlag RF  // Reduction flag
1593         , typename MT       // Type of the sparse matrix
1594         , typename OP >     // Type of the reduction operation
reduce_backend(const SparseMatrix<MT,false> & sm,OP op)1595 inline const SMatReduceExpr<MT,OP,RF> reduce_backend( const SparseMatrix<MT,false>& sm, OP op )
1596 {
1597    using ReturnType = const SMatReduceExpr<MT,OP,RF>;
1598    return ReturnType( *sm, std::move(op) );
1599 }
1600 /*! \endcond */
1601 //*************************************************************************************************
1602 
1603 
1604 //*************************************************************************************************
1605 /*! \cond BLAZE_INTERNAL */
1606 /*!\brief Backend implementation for custom reduction operations on column-major sparse matrices.
1607 // \ingroup sparse_matrix
1608 //
1609 // \param sm The given column-major sparse matrix for the reduction computation.
1610 // \param op The reduction operation.
1611 // \return The result of the reduction operation.
1612 */
1613 template< ReductionFlag RF  // Reduction flag
1614         , typename MT       // Type of the sparse matrix
1615         , typename OP >     // Type of the reduction operation
decltype(auto)1616 inline decltype(auto) reduce_backend( const SparseMatrix<MT,true>& sm, OP op )
1617 {
1618    constexpr ReductionFlag RF2( RF == rowwise ? columnwise : rowwise );
1619    return trans( reduce<RF2>( trans( *sm ), std::move(op) ) );
1620 }
1621 /*! \endcond */
1622 //*************************************************************************************************
1623 
1624 
1625 //*************************************************************************************************
1626 /*!\brief Performs a custom reduction operation on the given sparse matrix.
1627 // \ingroup sparse_matrix
1628 //
1629 // \param sm The given sparse matrix for the reduction computation.
1630 // \param op The reduction operation.
1631 // \return The result of the reduction operation.
1632 //
1633 // This function reduces the rows or columns of the given sparse matrix \a sm by means of the
1634 // given reduction operation \a op. In case the reduction flag \a RF is set to \a blaze::columnwise,
1635 // the elements of the matrix are reduced column-wise and the result is a row vector. In case
1636 // \a RF is set to \a blaze::rowwise, the elements of the matrix are reduced row-wise and the
1637 // result is a column vector:
1638 
1639    \code
1640    using blaze::columnwise;
1641 
1642    blaze::CompressedMatrix<double> A;
1643    blaze::DynamicVector<double,rowVector> colsum1, colsum2;
1644    // ... Resizing and initialization
1645 
1646    colsum1 = reduce<columnwise>( A, blaze::Add() );
1647    colsum2 = reduce<columnwise>( A, []( double a, double b ){ return a + b; } );
1648    \endcode
1649 
1650    \code
1651    using blaze::rowwise;
1652 
1653    blaze::CompressedMatrix<double> A;
1654    blaze::DynamicVector<double,columnVector> rowsum1, rowsum2;
1655    // ... Resizing and initialization
1656 
1657    rowsum1 = reduce<rowwise>( A, blaze::Add() );
1658    rowsum2 = reduce<rowwise>( A, []( double a, double b ){ return a + b; } );
1659    \endcode
1660 
1661 // Please note that the evaluation order of the reduction operation is unspecified. Thus the
1662 // behavior is non-deterministic if \a op is not associative or not commutative. Also, the
1663 // operation is undefined if the given reduction operation modifies the values.
1664 */
1665 template< ReductionFlag RF  // Reduction flag
1666         , typename MT       // Type of the sparse matrix
1667         , bool SO           // Storage order
1668         , typename OP >     // Type of the reduction operation
decltype(auto)1669 inline decltype(auto) reduce( const SparseMatrix<MT,SO>& sm, OP op )
1670 {
1671    BLAZE_FUNCTION_TRACE;
1672 
1673    BLAZE_STATIC_ASSERT_MSG( RF < 2UL, "Invalid reduction flag" );
1674 
1675    return reduce_backend<RF>( *sm, std::move(op) );
1676 }
1677 //*************************************************************************************************
1678 
1679 
1680 //*************************************************************************************************
1681 /*!\brief Reduces the given sparse matrix by means of addition.
1682 // \ingroup sparse_matrix
1683 //
1684 // \param sm The given sparse matrix for the reduction operation.
1685 // \return The result of the reduction operation.
1686 //
1687 // This function reduces the non-zero elements of the given sparse matrix \a sm by means of
1688 // addition:
1689 
1690    \code
1691    blaze::CompressedMatrix<int> A{ { 1, 2 }, { 3, 4 } };
1692 
1693    const int totalsum = sum( A );  // Results in 10
1694    \endcode
1695 
1696 // Please note that the evaluation order of the reduction operation is unspecified.
1697 */
1698 template< typename MT  // Type of the sparse matrix
1699         , bool SO >    // Storage order
decltype(auto)1700 inline decltype(auto) sum( const SparseMatrix<MT,SO>& sm )
1701 {
1702    BLAZE_FUNCTION_TRACE;
1703 
1704    return reduce( *sm, Add() );
1705 }
1706 //*************************************************************************************************
1707 
1708 
1709 //*************************************************************************************************
1710 /*!\brief Reduces the given sparse matrix by means of addition.
1711 // \ingroup sparse_matrix
1712 //
1713 // \param sm The given sparse matrix for the reduction operation.
1714 // \return The result of the reduction operation.
1715 //
1716 // This function reduces the non-zero elements of the rows or columns of the given sparse matrix
1717 // \a sm by means of addition. In case the reduction flag \a RF is set to \a blaze::columnwise,
1718 // the elements of the matrix are reduced column-wise and the result is a row vector. In case
1719 // \a RF is set to \a blaze::rowwise, the elements of the matrix are reduced row-wise and the
1720 // result is a column vector:
1721 
1722    \code
1723    using blaze::columnwise;
1724 
1725    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1726    blaze::DynamicVector<int,rowVector> colsum;
1727 
1728    colsum = sum<columnwise>( A );  // Results in ( 2, 3, 6 )
1729    \endcode
1730 
1731    \code
1732    using blaze::rowwise;
1733 
1734    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1735    blaze::DynamicVector<int,columnVector> rowsum;
1736 
1737    rowsum = sum<rowwise>( A );  // Results in ( 3, 8 )
1738    \endcode
1739 
1740 // Please note that the evaluation order of the reduction operation is unspecified.
1741 */
1742 template< ReductionFlag RF  // Reduction flag
1743         , typename MT       // Type of the sparse matrix
1744         , bool SO >         // Storage order
decltype(auto)1745 inline decltype(auto) sum( const SparseMatrix<MT,SO>& sm )
1746 {
1747    BLAZE_FUNCTION_TRACE;
1748 
1749    return reduce<RF>( *sm, Add() );
1750 }
1751 //*************************************************************************************************
1752 
1753 
1754 //*************************************************************************************************
1755 /*!\brief Reduces the given sparse matrix by means of multiplication.
1756 // \ingroup sparse_matrix
1757 //
1758 // \param sm The given sparse matrix for the reduction operation.
1759 // \return The result of the reduction operation.
1760 //
1761 // This function reduces the non-zero elements of the given sparse matrix \a sm by means of
1762 // multiplication:
1763 
1764    \code
1765    blaze::CompressedMatrix<int> A{ { 1, 2 }, { 3, 4 } };
1766 
1767    const int totalprod = prod( A );  // Results in 24
1768    \endcode
1769 
1770 // Please note that the evaluation order of the reduction operation is unspecified.
1771 */
1772 template< typename MT  // Type of the sparse matrix
1773         , bool SO >    // Storage order
decltype(auto)1774 inline decltype(auto) prod( const SparseMatrix<MT,SO>& sm )
1775 {
1776    BLAZE_FUNCTION_TRACE;
1777 
1778    return reduce( *sm, Mult() );
1779 }
1780 //*************************************************************************************************
1781 
1782 
1783 //*************************************************************************************************
1784 /*!\brief Reduces the given sparse matrix by means of multiplication.
1785 // \ingroup sparse_matrix
1786 //
1787 // \param sm The given sparse matrix for the reduction operation.
1788 // \return The result of the reduction operation.
1789 //
1790 // This function reduces the non-zero elements of the rows or columns of the given sparse
1791 // matrix \a sm by means of multiplication. In case the reduction flag \a RF is set to
1792 // \a blaze::columnwise, the elements of the matrix are reduced column-wise and the result
1793 // is a row vector. In case \a RF is set to \a blaze::rowwise, the elements of the matrix
1794 // are reduced row-wise and the result is a column vector:
1795 
1796    \code
1797    using blaze::columnwise;
1798 
1799    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1800    blaze::DynamicVector<int,rowVector> colsum;
1801 
1802    colsum = sum<columnwise>( A );  // Results in ( 1, 3, 8 )
1803    \endcode
1804 
1805    \code
1806    using blaze::rowwise;
1807 
1808    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1809    blaze::DynamicVector<int,columnVector> rowsum;
1810 
1811    rowsum = sum<rowwise>( A );  // Results in ( 2, 12 )
1812    \endcode
1813 
1814 // Please note that the evaluation order of the reduction operation is unspecified.
1815 */
1816 template< ReductionFlag RF  // Reduction flag
1817         , typename MT       // Type of the sparse matrix
1818         , bool SO >         // Storage order
decltype(auto)1819 inline decltype(auto) prod( const SparseMatrix<MT,SO>& sm )
1820 {
1821    BLAZE_FUNCTION_TRACE;
1822 
1823    return reduce<RF>( *sm, Mult() );
1824 }
1825 //*************************************************************************************************
1826 
1827 
1828 //*************************************************************************************************
1829 /*!\brief Returns the smallest element of the sparse matrix.
1830 // \ingroup sparse_matrix
1831 //
1832 // \param sm The given sparse matrix.
1833 // \return The smallest sparse matrix element.
1834 //
1835 // This function returns the smallest non-zero element of the given sparse matrix. This function
1836 // can only be used for element types that support the smaller-than relationship. In case the
1837 // given matrix currently has either 0 rows or 0 columns, the returned value is the default
1838 // value (e.g. 0 in case of fundamental data types).
1839 //
1840 // \note In case the sparse matrix is not completely filled, the implicit zero elements are NOT
1841 // taken into account. Example: the following compressed matrix has only 2 non-zero elements.
1842 // However, the minimum of this matrix is 1:
1843 
1844    \code
1845    blaze::CompressedMatrix<int> A{ { 1, 0 }, { 3, 0 } };
1846 
1847    const int totalmin = min( A );  // Results in 1
1848    \endcode
1849 */
1850 template< typename MT  // Type of the sparse matrix
1851         , bool SO >    // Storage order
decltype(auto)1852 inline decltype(auto) min( const SparseMatrix<MT,SO>& sm )
1853 {
1854    BLAZE_FUNCTION_TRACE;
1855 
1856    return reduce( *sm, Min() );
1857 }
1858 //*************************************************************************************************
1859 
1860 
1861 //*************************************************************************************************
1862 /*!\brief Returns the smallest element of each row/columns of the sparse matrix.
1863 // \ingroup sparse_matrix
1864 //
1865 // \param sm The given sparse matrix.
1866 // \return The smallest elements in each row/column.
1867 //
1868 // This function returns the smallest non-zero element of each row/column of the given sparse
1869 // matrix \a sm. In case the reduction flag \a RF is set to \a blaze::columnwise, a row
1870 // vector containing the smallest element of each column is returned. In case \a RF is set to
1871 // \a blaze::rowwise, a column vector containing the smallest element of each row is returned.
1872 //
1873 // \note In case the sparse matrix is not completely filled, the implicit zero elements are NOT
1874 // taken into account:
1875 
1876    \code
1877    using blaze::columnwise;
1878 
1879    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1880    blaze::DynamicVector<int,rowVector> colmin;
1881 
1882    colmin = min<columnwise>( A );  // Results in ( 1, 3, 2 )
1883    \endcode
1884 
1885    \code
1886    using blaze::rowwise;
1887 
1888    blaze::CompressedMatrix<int> A{ { 1, 0, 2 }, { 1, 3, 4 } };
1889    blaze::DynamicVector<int,columnVector> rowmin;
1890 
1891    rowmin = min<rowwise>( A );  // Results in ( 1, 1 )
1892    \endcode
1893 */
1894 template< ReductionFlag RF  // Reduction flag
1895         , typename MT       // Type of the sparse matrix
1896         , bool SO >         // Storage order
decltype(auto)1897 inline decltype(auto) min( const SparseMatrix<MT,SO>& sm )
1898 {
1899    BLAZE_FUNCTION_TRACE;
1900 
1901    return reduce<RF>( *sm, Min() );
1902 }
1903 //*************************************************************************************************
1904 
1905 
1906 //*************************************************************************************************
1907 /*!\brief Returns the largest element of the sparse matrix.
1908 // \ingroup sparse_matrix
1909 //
1910 // \param sm The given sparse matrix.
1911 // \return The largest sparse matrix element.
1912 //
1913 // This function returns the largest non-zero element of the given sparse matrix. This function
1914 // can only be used for element types that support the smaller-than relationship. In case the
1915 // given matrix currently has either 0 rows or 0 columns, the returned value is the default
1916 // value (e.g. 0 in case of fundamental data types).
1917 //
1918 // \note In case the sparse matrix is not completely filled, the implicit zero elements are NOT
1919 // taken into account. Example: the following compressed matrix has only 2 non-zero elements.
1920 // However, the maximum of this matrix is -1:
1921 
1922    \code
1923    blaze::CompressedMatrix<int> A{ { -1, 0 }, { -3, 0 } };
1924 
1925    const int totalmax = max( A );  // Results in -1
1926    \endcode
1927 */
1928 template< typename MT  // Type of the sparse matrix
1929         , bool SO >    // Storage order
decltype(auto)1930 inline decltype(auto) max( const SparseMatrix<MT,SO>& sm )
1931 {
1932    BLAZE_FUNCTION_TRACE;
1933 
1934    return reduce( *sm, Max() );
1935 }
1936 //*************************************************************************************************
1937 
1938 
1939 //*************************************************************************************************
1940 /*!\brief Returns the largest element of each row/columns of the sparse matrix.
1941 // \ingroup sparse_matrix
1942 //
1943 // \param sm The given sparse matrix.
1944 // \return The largest elements in each row/column.
1945 //
1946 // This function returns the largest element of each row/column of the given sparse matrix \a sm.
1947 // In case the reduction flag \a RF is set to \a blaze::columnwise, a row vector containing the
1948 // largest element of each column is returned. In case \a RF is set to \a blaze::rowwise, a column
1949 // vector containing the largest element of each row is returned.
1950 //
1951 // \note In case the sparse matrix is not completely filled, the implicit zero elements are NOT
1952 // taken into account:
1953 
1954    \code
1955    using blaze::columnwise;
1956 
1957    blaze::CompressedMatrix<int> A{ { -1, 0, -2 }, { -1, -3, -4 } };
1958    blaze::DynamicVector<int,rowVector> colmax;
1959 
1960    colmax = max<columnwise>( A );  // Results in ( -1, -3, -2 )
1961    \endcode
1962 
1963    \code
1964    using blaze::rowwise;
1965 
1966    blaze::CompressedMatrix<int> A{ { -1, 0, -2 }, { -1, -3, -4 } };
1967    blaze::DynamicVector<int,columnVector> rowmax;
1968 
1969    rowmax = max<rowwise>( A );  // Results in ( -1, -1 )
1970    \endcode
1971 */
1972 template< ReductionFlag RF  // Reduction flag
1973         , typename MT       // Type of the sparse matrix
1974         , bool SO >         // Storage order
decltype(auto)1975 inline decltype(auto) max( const SparseMatrix<MT,SO>& sm )
1976 {
1977    BLAZE_FUNCTION_TRACE;
1978 
1979    return reduce<RF>( *sm, Max() );
1980 }
1981 //*************************************************************************************************
1982 
1983 } // namespace blaze
1984 
1985 #endif
1986