1 //=================================================================================================
2 /*!
3 //  \file blaze/math/expressions/DMatTSMatAddExpr.h
4 //  \brief Header file for the dense matrix/transpose sparse matrix addition 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_DMATTSMATADDEXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_DMATTSMATADDEXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <utility>
44 #include <blaze/math/Aliases.h>
45 #include <blaze/math/constraints/ColumnMajorMatrix.h>
46 #include <blaze/math/constraints/DenseMatrix.h>
47 #include <blaze/math/constraints/MatMatAddExpr.h>
48 #include <blaze/math/constraints/RequiresEvaluation.h>
49 #include <blaze/math/constraints/RowMajorMatrix.h>
50 #include <blaze/math/constraints/SparseMatrix.h>
51 #include <blaze/math/constraints/StorageOrder.h>
52 #include <blaze/math/Exception.h>
53 #include <blaze/math/expressions/Computation.h>
54 #include <blaze/math/expressions/DenseMatrix.h>
55 #include <blaze/math/expressions/Forward.h>
56 #include <blaze/math/expressions/MatMatAddExpr.h>
57 #include <blaze/math/shims/Serial.h>
58 #include <blaze/math/traits/AddTrait.h>
59 #include <blaze/math/typetraits/IsExpression.h>
60 #include <blaze/math/typetraits/IsOperation.h>
61 #include <blaze/math/typetraits/IsTemporary.h>
62 #include <blaze/math/typetraits/IsZero.h>
63 #include <blaze/util/Assert.h>
64 #include <blaze/util/EnableIf.h>
65 #include <blaze/util/FunctionTrace.h>
66 #include <blaze/util/IntegralConstant.h>
67 #include <blaze/util/MaybeUnused.h>
68 #include <blaze/util/mpl/If.h>
69 #include <blaze/util/Types.h>
70 #include <blaze/util/typetraits/IsSame.h>
71 
72 
73 namespace blaze {
74 
75 //=================================================================================================
76 //
77 //  CLASS DMATTSMATADDEXPR
78 //
79 //=================================================================================================
80 
81 //*************************************************************************************************
82 /*!\brief Expression object for dense matrix-sparse matrix additions.
83 // \ingroup dense_matrix_expression
84 //
85 // The DMatTSMatAddExpr class represents the compile time expression for additions between
86 // a row-major dense matrix and a column-major sparse matrix.
87 */
88 template< typename MT1   // Type of the left-hand side dense matrix
89         , typename MT2 > // Type of the right-hand side sparse matrix
90 class DMatTSMatAddExpr
91    : public MatMatAddExpr< DenseMatrix< DMatTSMatAddExpr<MT1,MT2>, false > >
92    , private Computation
93 {
94  private:
95    //**Type definitions****************************************************************************
96   using RT1 = ResultType_t<MT1>;  //!< Result type of the left-hand side dense matrix expression.
97   using RT2 = ResultType_t<MT2>;  //!< Result type of the right-hand side sparse matrix expression.
98   using RN1 = ReturnType_t<MT1>;  //!< Return type of the left-hand side dense matrix expression.
99   using RN2 = ReturnType_t<MT2>;  //!< Return type of the right-hand side sparse matrix expression.
100    //**********************************************************************************************
101 
102    //**Return type evaluation**********************************************************************
103    //! Compilation switch for the selection of the subscript operator return type.
104    /*! The \a returnExpr compile time constant expression is a compilation switch for the
105        selection of the \a ReturnType. If either matrix operand returns a temporary vector
106        or matrix, \a returnExpr will be set to \a false and the subscript operator will
107        return it's result by value. Otherwise \a returnExpr will be set to \a true and
108        the subscript operator may return it's result as an expression. */
109    static constexpr bool returnExpr = ( !IsTemporary_v<RN1> && !IsTemporary_v<RN2> );
110 
111    //! Expression return type for the subscript operator.
112    using ExprReturnType = decltype( std::declval<RN1>() + std::declval<RN2>() );
113    //**********************************************************************************************
114 
115    //**Parallel evaluation strategy****************************************************************
116    /*! \cond BLAZE_INTERNAL */
117    //! Helper variable template for the explicit application of the SFINAE principle.
118    /*! This variable template is a helper for the selection of the parallel evaluation strategy.
119        In case at least one of the two matrix operands is not SMP assignable, the variable is set
120        to 1 and the expression specific evaluation strategy is selected. Otherwise the variable
121        is set to 0 and the default strategy is chosen. */
122    template< typename MT >
123    static constexpr bool UseSMPAssign_v = ( !MT1::smpAssignable || !MT2::smpAssignable );
124    /*! \endcond */
125    //**********************************************************************************************
126 
127  public:
128    //**Type definitions****************************************************************************
129    //! Type of this DMatTSMatAddExpr instance.
130    using This = DMatTSMatAddExpr<MT1,MT2>;
131 
132    //! Base type of this DMatTSMatAddExpr instance.
133    using BaseType = MatMatAddExpr< DenseMatrix<This,false> >;
134 
135    using ResultType    = AddTrait_t<RT1,RT2>;          //!< Result type for expression template evaluations.
136    using OppositeType  = OppositeType_t<ResultType>;   //!< Result type with opposite storage order for expression template evaluations.
137    using TransposeType = TransposeType_t<ResultType>;  //!< Transpose type for expression template evaluations.
138    using ElementType   = ElementType_t<ResultType>;    //!< Resulting element type.
139 
140    //! Return type for expression template evaluations.
141    using ReturnType = const If_t< returnExpr, ExprReturnType, ElementType >;
142 
143    //! Data type for composite expression templates.
144    using CompositeType = const ResultType;
145 
146    //! Composite type of the left-hand side dense matrix expression.
147    using LeftOperand = If_t< IsExpression_v<MT1>, const MT1, const MT1& >;
148 
149    //! Composite type of the right-hand side sparse matrix expression.
150    using RightOperand = If_t< IsExpression_v<MT2>, const MT2, const MT2& >;
151    //**********************************************************************************************
152 
153    //**Compilation flags***************************************************************************
154    //! Compilation switch for the expression template evaluation strategy.
155    static constexpr bool simdEnabled = false;
156 
157    //! Compilation switch for the expression template assignment strategy.
158    static constexpr bool smpAssignable = false;
159    //**********************************************************************************************
160 
161    //**Constructor*********************************************************************************
162    /*!\brief Constructor for the DMatTSMatAddExpr class.
163    //
164    // \param lhs The left-hand side dense matrix operand of the addition expression.
165    // \param rhs The right-hand side sparse matrix operand of the addition expression.
166    */
DMatTSMatAddExpr(const MT1 & lhs,const MT2 & rhs)167    inline DMatTSMatAddExpr( const MT1& lhs, const MT2& rhs ) noexcept
168       : lhs_( lhs )  // Left-hand side dense matrix of the addition expression
169       , rhs_( rhs )  // Right-hand side sparse matrix of the addition expression
170    {
171       BLAZE_INTERNAL_ASSERT( lhs.rows()    == rhs.rows()   , "Invalid number of rows"    );
172       BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.columns(), "Invalid number of columns" );
173    }
174    //**********************************************************************************************
175 
176    //**Access operator*****************************************************************************
177    /*!\brief 2D-access to the matrix elements.
178    //
179    // \param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$.
180    // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
181    // \return The resulting value.
182    */
operator()183    inline ReturnType operator()( size_t i, size_t j ) const {
184       BLAZE_INTERNAL_ASSERT( i < lhs_.rows()   , "Invalid row access index"    );
185       BLAZE_INTERNAL_ASSERT( j < lhs_.columns(), "Invalid column access index" );
186       return lhs_(i,j) + rhs_(i,j);
187    }
188    //**********************************************************************************************
189 
190    //**At function*********************************************************************************
191    /*!\brief Checked access to the matrix elements.
192    //
193    // \param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$.
194    // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
195    // \return The resulting value.
196    // \exception std::out_of_range Invalid matrix access index.
197    */
at(size_t i,size_t j)198    inline ReturnType at( size_t i, size_t j ) const {
199       if( i >= lhs_.rows() ) {
200          BLAZE_THROW_OUT_OF_RANGE( "Invalid row access index" );
201       }
202       if( j >= lhs_.columns() ) {
203          BLAZE_THROW_OUT_OF_RANGE( "Invalid column access index" );
204       }
205       return (*this)(i,j);
206    }
207    //**********************************************************************************************
208 
209    //**Rows function*******************************************************************************
210    /*!\brief Returns the current number of rows of the matrix.
211    //
212    // \return The number of rows of the matrix.
213    */
rows()214    inline size_t rows() const noexcept {
215       return lhs_.rows();
216    }
217    //**********************************************************************************************
218 
219    //**Columns function****************************************************************************
220    /*!\brief Returns the current number of columns of the matrix.
221    //
222    // \return The number of columns of the matrix.
223    */
columns()224    inline size_t columns() const noexcept {
225       return lhs_.columns();
226    }
227    //**********************************************************************************************
228 
229    //**Left operand access*************************************************************************
230    /*!\brief Returns the left-hand side dense matrix operand.
231    //
232    // \return The left-hand side dense matrix operand.
233    */
leftOperand()234    inline LeftOperand leftOperand() const {
235       return lhs_;
236    }
237    //**********************************************************************************************
238 
239    //**Right operand access************************************************************************
240    /*!\brief Returns the right-hand side transpose sparse matrix operand.
241    //
242    // \return The right-hand side transpose sparse matrix operand.
243    */
rightOperand()244    inline RightOperand rightOperand() const noexcept {
245       return rhs_;
246    }
247    //**********************************************************************************************
248 
249    //**********************************************************************************************
250    /*!\brief Returns whether the expression can alias with the given address \a alias.
251    //
252    // \param alias The alias to be checked.
253    // \return \a true in case the expression can alias, \a false otherwise.
254    */
255    template< typename T >
canAlias(const T * alias)256    inline bool canAlias( const T* alias ) const noexcept {
257       return ( IsExpression_v<MT1> && lhs_.canAlias( alias ) ) ||
258              ( rhs_.canAlias( alias ) );
259    }
260    //**********************************************************************************************
261 
262    //**********************************************************************************************
263    /*!\brief Returns whether the expression is aliased with the given address \a alias.
264    //
265    // \param alias The alias to be checked.
266    // \return \a true in case an alias effect is detected, \a false otherwise.
267    */
268    template< typename T >
isAliased(const T * alias)269    inline bool isAliased( const T* alias ) const noexcept {
270       return ( lhs_.canAlias( alias ) || rhs_.canAlias( alias ) );
271    }
272    //**********************************************************************************************
273 
274  private:
275    //**Member variables****************************************************************************
276    LeftOperand  lhs_;  //!< Left-hand side dense matrix of the addition expression.
277    RightOperand rhs_;  //!< Right-hand side sparse matrix of the addition expression.
278    //**********************************************************************************************
279 
280    //**Assignment to dense matrices****************************************************************
281    /*! \cond BLAZE_INTERNAL */
282    /*!\brief Assignment of a dense matrix-transpose sparse matrix addition to a dense matrix.
283    // \ingroup dense_matrix
284    //
285    // \param lhs The target left-hand side dense matrix.
286    // \param rhs The right-hand side addition expression to be assigned.
287    // \return void
288    //
289    // This function implements the performance optimized assignment of a dense matrix-transpose
290    // sparse matrix addition expression to a dense matrix.
291    */
292    template< typename MT  // Type of the target dense matrix
293            , bool SO2 >   // Storage order of the target dense matrix
assign(DenseMatrix<MT,SO2> & lhs,const DMatTSMatAddExpr & rhs)294    friend inline void assign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
295    {
296       BLAZE_FUNCTION_TRACE;
297 
298       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
299       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
300 
301       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
302          addAssign( *lhs, rhs.rhs_ );
303       }
304       else {
305          assign   ( *lhs, rhs.lhs_ );
306          addAssign( *lhs, rhs.rhs_ );
307       }
308    }
309    /*! \endcond */
310    //**********************************************************************************************
311 
312    //**Assignment to sparse matrices***************************************************************
313    /*! \cond BLAZE_INTERNAL */
314    /*!\brief Assignment of a dense matrix-transpose sparse matrix addition to a sparse matrix.
315    // \ingroup dense_matrix
316    //
317    // \param lhs The target left-hand side sparse matrix.
318    // \param rhs The right-hand side addition expression to be assigned.
319    // \return void
320    //
321    // This function implements the performance optimized assignment of a dense matrix-transpose
322    // sparse matrix addition expression to a sparse matrix.
323    */
324    template< typename MT  // Type of the target sparse matrix
325            , bool SO2 >   // Storage order of the target sparse matrix
assign(SparseMatrix<MT,SO2> & lhs,const DMatTSMatAddExpr & rhs)326    friend inline void assign( SparseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
327    {
328       BLAZE_FUNCTION_TRACE;
329 
330       using TmpType = If_t< SO2, OppositeType, ResultType >;
331 
332       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
333       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( OppositeType );
334       BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( ResultType );
335       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OppositeType );
336       BLAZE_CONSTRAINT_MATRICES_MUST_HAVE_SAME_STORAGE_ORDER( MT, TmpType );
337       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( TmpType );
338 
339       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
340       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
341 
342       const TmpType tmp( serial( rhs ) );
343       assign( *lhs, tmp );
344    }
345    /*! \endcond */
346    //**********************************************************************************************
347 
348    //**Addition assignment to dense matrices*******************************************************
349    /*! \cond BLAZE_INTERNAL */
350    /*!\brief Addition assignment of a dense matrix-transpose sparse matrix addition to a dense
351    //        matrix.
352    // \ingroup dense_matrix
353    //
354    // \param lhs The target left-hand side dense matrix.
355    // \param rhs The right-hand side addition expression to be added.
356    // \return void
357    //
358    // This function implements the performance optimized addition assignment of a dense matrix-
359    // transpose sparse matrix addition expression to a dense matrix.
360    */
361    template< typename MT  // Type of the target dense matrix
362            , bool SO2 >   // Storage order of the target dense matrix
addAssign(DenseMatrix<MT,SO2> & lhs,const DMatTSMatAddExpr & rhs)363    friend inline void addAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
364    {
365       BLAZE_FUNCTION_TRACE;
366 
367       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
368       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
369 
370       addAssign( *lhs, rhs.lhs_ );
371       addAssign( *lhs, rhs.rhs_ );
372    }
373    /*! \endcond */
374    //**********************************************************************************************
375 
376    //**Addition assignment to sparse matrices******************************************************
377    // No special implementation for the addition assignment to sparse matrices.
378    //**********************************************************************************************
379 
380    //**Subtraction assignment to dense matrices****************************************************
381    /*! \cond BLAZE_INTERNAL */
382    /*!\brief Subtraction assignment of a dense matrix-transpose sparse matrix addition to a dense
383    //        matrix.
384    // \ingroup dense_matrix
385    //
386    // \param lhs The target left-hand side dense matrix.
387    // \param rhs The right-hand side addition expression to be subtracted.
388    // \return void
389    //
390    // This function implements the performance optimized subtraction assignment of a dense matrix-
391    // transpose sparse matrix addition expression to a dense matrix.
392    */
393    template< typename MT  // Type of the target dense matrix
394            , bool SO2 >   // Storage order of the target dense matrix
subAssign(DenseMatrix<MT,SO2> & lhs,const DMatTSMatAddExpr & rhs)395    friend inline void subAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
396    {
397       BLAZE_FUNCTION_TRACE;
398 
399       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
400       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
401 
402       subAssign( *lhs, rhs.lhs_ );
403       subAssign( *lhs, rhs.rhs_ );
404    }
405    /*! \endcond */
406    //**********************************************************************************************
407 
408    //**Subtraction assignment to sparse matrices***************************************************
409    // No special implementation for the subtraction assignment to sparse matrices.
410    //**********************************************************************************************
411 
412    //**Schur product assignment to dense matrices**************************************************
413    /*! \cond BLAZE_INTERNAL */
414    /*!\brief Schur product assignment of a dense matrix-transpose sparse matrix addition to a
415    //        dense matrix.
416    // \ingroup dense_matrix
417    //
418    // \param lhs The target left-hand side dense matrix.
419    // \param rhs The right-hand side addition expression for the Schur product.
420    // \return void
421    //
422    // This function implements the performance optimized Schur product assignment of a dense
423    // matrix-transpose sparse matrix addition expression to a dense matrix.
424    */
425    template< typename MT  // Type of the target dense matrix
426            , bool SO2 >   // Storage order of the target dense matrix
schurAssign(DenseMatrix<MT,SO2> & lhs,const DMatTSMatAddExpr & rhs)427    friend inline void schurAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
428    {
429       BLAZE_FUNCTION_TRACE;
430 
431       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
432       BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( ResultType );
433       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
434 
435       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
436       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
437 
438       const ResultType tmp( serial( rhs ) );
439       schurAssign( *lhs, tmp );
440    }
441    /*! \endcond */
442    //**********************************************************************************************
443 
444    //**Schur product assignment to sparse matrices*************************************************
445    // No special implementation for the Schur product assignment to sparse matrices.
446    //**********************************************************************************************
447 
448    //**Multiplication assignment to dense matrices*************************************************
449    // No special implementation for the multiplication assignment to dense matrices.
450    //**********************************************************************************************
451 
452    //**Multiplication assignment to sparse matrices************************************************
453    // No special implementation for the multiplication assignment to sparse matrices.
454    //**********************************************************************************************
455 
456    //**SMP assignment to dense matrices************************************************************
457    /*! \cond BLAZE_INTERNAL */
458    /*!\brief SMP assignment of a dense matrix-transpose sparse matrix addition to a dense matrix.
459    // \ingroup dense_matrix
460    //
461    // \param lhs The target left-hand side dense matrix.
462    // \param rhs The right-hand side addition expression to be assigned.
463    // \return void
464    //
465    // This function implements the performance optimized SMP assignment of a dense matrix-transpose
466    // sparse matrix addition expression to a dense matrix. Due to the explicit application of the
467    // SFINAE principle, this function can only be selected by the compiler in case the expression
468    // specific parallel evaluation strategy is selected.
469    */
470    template< typename MT  // Type of the target dense matrix
471            , bool SO2 >   // Storage order of the target dense matrix
472    friend inline auto smpAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
473       -> EnableIf_t< UseSMPAssign_v<MT> >
474    {
475       BLAZE_FUNCTION_TRACE;
476 
477       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
478       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
479 
480       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
481          smpAddAssign( *lhs, rhs.rhs_ );
482       }
483       else {
484          smpAssign   ( *lhs, rhs.lhs_ );
485          smpAddAssign( *lhs, rhs.rhs_ );
486       }
487    }
488    /*! \endcond */
489    //**********************************************************************************************
490 
491    //**SMP assignment to sparse matrices***********************************************************
492    /*! \cond BLAZE_INTERNAL */
493    /*!\brief SMP assignment of a dense matrix-transpose sparse matrix addition to a sparse matrix.
494    // \ingroup dense_matrix
495    //
496    // \param lhs The target left-hand side sparse matrix.
497    // \param rhs The right-hand side addition expression to be assigned.
498    // \return void
499    //
500    // This function implements the performance optimized SMP assignment of a dense matrix-transpose
501    // sparse matrix addition expression to a sparse matrix. Due to the explicit application of the
502    // SFINAE principle, this function can only be selected by the compiler in case the expression
503    // specific parallel evaluation strategy is selected.
504    */
505    template< typename MT  // Type of the target sparse matrix
506            , bool SO2 >   // Storage order of the target sparse matrix
507    friend inline auto smpAssign( SparseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
508       -> EnableIf_t< UseSMPAssign_v<MT> >
509    {
510       BLAZE_FUNCTION_TRACE;
511 
512       using TmpType = If_t< SO2, OppositeType, ResultType >;
513 
514       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
515       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( OppositeType );
516       BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( ResultType );
517       BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( OppositeType );
518       BLAZE_CONSTRAINT_MATRICES_MUST_HAVE_SAME_STORAGE_ORDER( MT, TmpType );
519       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( TmpType );
520 
521       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
522       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
523 
524       const TmpType tmp( rhs );
525       smpAssign( *lhs, tmp );
526    }
527    /*! \endcond */
528    //**********************************************************************************************
529 
530    //**SMP addition assignment to dense matrices***************************************************
531    /*! \cond BLAZE_INTERNAL */
532    /*!\brief SMP addition assignment of a dense matrix-transpose sparse matrix addition to a dense
533    //        matrix.
534    // \ingroup dense_matrix
535    //
536    // \param lhs The target left-hand side dense matrix.
537    // \param rhs The right-hand side addition expression to be added.
538    // \return void
539    //
540    // This function implements the performance optimized addition assignment of a dense matrix-
541    // transpose sparse matrix addition expression to a dense matrix. Due to the explicit application
542    // of the SFINAE principle, this function can only be selected by the compiler in case the
543    // expression specific parallel evaluation strategy is selected.
544    */
545    template< typename MT  // Type of the target dense matrix
546            , bool SO2 >   // Storage order of the target dense matrix
547    friend inline auto smpAddAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
548       -> EnableIf_t< UseSMPAssign_v<MT> >
549    {
550       BLAZE_FUNCTION_TRACE;
551 
552       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
553       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
554 
555       smpAddAssign( *lhs, rhs.lhs_ );
556       smpAddAssign( *lhs, rhs.rhs_ );
557    }
558    /*! \endcond */
559    //**********************************************************************************************
560 
561    //**SMP addition assignment to sparse matrices**************************************************
562    // No special implementation for the SMP addition assignment to sparse matrices.
563    //**********************************************************************************************
564 
565    //**SMP subtraction assignment to dense matrices************************************************
566    /*! \cond BLAZE_INTERNAL */
567    /*!\brief SMP subtraction assignment of a dense matrix-transpose sparse matrix addition to a dense
568    //        matrix.
569    // \ingroup dense_matrix
570    //
571    // \param lhs The target left-hand side dense matrix.
572    // \param rhs The right-hand side addition expression to be subtracted.
573    // \return void
574    //
575    // This function implements the performance optimized SMP subtraction assignment of a dense
576    // matrix-transpose sparse matrix addition expression to a dense matrix. Due to the explicit
577    // application of the SFINAE principle, this function can only be selected by the compiler in
578    // case the expression specific parallel evaluation strategy is selected.
579    */
580    template< typename MT  // Type of the target dense matrix
581            , bool SO2 >   // Storage order of the target dense matrix
582    friend inline auto smpSubAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
583       -> EnableIf_t< UseSMPAssign_v<MT> >
584    {
585       BLAZE_FUNCTION_TRACE;
586 
587       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
588       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
589 
590       smpSubAssign( *lhs, rhs.lhs_ );
591       smpSubAssign( *lhs, rhs.rhs_ );
592    }
593    /*! \endcond */
594    //**********************************************************************************************
595 
596    //**SMP subtraction assignment to sparse matrices***********************************************
597    // No special implementation for the SMP subtraction assignment to sparse matrices.
598    //**********************************************************************************************
599 
600    //**SMP Schur product assignment to dense matrices**********************************************
601    /*! \cond BLAZE_INTERNAL */
602    /*!\brief SMP Schur product assignment of a dense matrix-transpose sparse matrix addition to
603    //        a dense matrix.
604    // \ingroup dense_matrix
605    //
606    // \param lhs The target left-hand side dense matrix.
607    // \param rhs The right-hand side addition expression for the Schur product.
608    // \return void
609    //
610    // This function implements the performance optimized SMP Schur product assignment of a dense
611    // matrix-transpose sparse matrix addition expression to a dense matrix. Due to the explicit
612    // application of the SFINAE principle, this function can only be selected by the compiler in
613    // case the expression specific parallel evaluation strategy is selected.
614    */
615    template< typename MT  // Type of the target dense matrix
616            , bool SO2 >   // Storage order of the target dense matrix
617    friend inline auto smpSchurAssign( DenseMatrix<MT,SO2>& lhs, const DMatTSMatAddExpr& rhs )
618       -> EnableIf_t< UseSMPAssign_v<MT> >
619    {
620       BLAZE_FUNCTION_TRACE;
621 
622       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
623       BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( ResultType );
624       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
625 
626       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
627       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
628 
629       const ResultType tmp( rhs );
630       smpSchurAssign( *lhs, tmp );
631    }
632    /*! \endcond */
633    //**********************************************************************************************
634 
635    //**SMP Schur product assignment to sparse matrices*********************************************
636    // No special implementation for the SMP Schur product assignment to sparse matrices.
637    //**********************************************************************************************
638 
639    //**SMP multiplication assignment to dense matrices*********************************************
640    // No special implementation for the SMP multiplication assignment to dense matrices.
641    //**********************************************************************************************
642 
643    //**SMP multiplication assignment to sparse matrices********************************************
644    // No special implementation for the SMP multiplication assignment to sparse matrices.
645    //**********************************************************************************************
646 
647    //**Compile time checks*************************************************************************
648    /*! \cond BLAZE_INTERNAL */
649    BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( MT1 );
650    BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE( MT2 );
651    BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE( MT1 );
652    BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE( MT2 );
653    BLAZE_CONSTRAINT_MUST_FORM_VALID_MATMATADDEXPR( MT1, MT2 );
654    /*! \endcond */
655    //**********************************************************************************************
656 };
657 //*************************************************************************************************
658 
659 
660 
661 
662 //=================================================================================================
663 //
664 //  GLOBAL BINARY ARITHMETIC OPERATORS
665 //
666 //=================================================================================================
667 
668 //*************************************************************************************************
669 /*! \cond BLAZE_INTERNAL */
670 /*!\brief Backend implementation of the addition between a row-major dense matrix and a
671 //        column-major sparse matrix (\f$ A=B+C \f$).
672 // \ingroup dense_matrix
673 //
674 // \param lhs The left-hand side dense matrix for the addition.
675 // \param rhs The right-hand side sparse matrix for the addition.
676 // \return The sum of the two matrices.
677 //
678 // This function implements a performance optimized treatment of the addition between a row-major
679 // dense matrix and a column-major sparse matrix.
680 */
681 template< typename MT1  // Type of the left-hand side dense matrix
682         , typename MT2  // Type of the right-hand side sparse matrix
683         , DisableIf_t< IsZero_v<MT2> &&
684                        IsSame_v< ElementType_t<MT1>, ElementType_t<MT2> > >* = nullptr >
685 inline const DMatTSMatAddExpr<MT1,MT2>
dmattsmatadd(const DenseMatrix<MT1,false> & lhs,const SparseMatrix<MT2,true> & rhs)686    dmattsmatadd( const DenseMatrix<MT1,false>& lhs, const SparseMatrix<MT2,true>& rhs )
687 {
688    BLAZE_FUNCTION_TRACE;
689 
690    BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == (*rhs).rows()   , "Invalid number of rows"    );
691    BLAZE_INTERNAL_ASSERT( (*lhs).columns() == (*rhs).columns(), "Invalid number of columns" );
692 
693    return DMatTSMatAddExpr<MT1,MT2>( *lhs, *rhs );
694 }
695 /*! \endcond */
696 //*************************************************************************************************
697 
698 
699 //*************************************************************************************************
700 /*! \cond BLAZE_INTERNAL */
701 /*!\brief Backend implementation of the addition between a row-major dense matrix and a
702 //        column-major zero matrix (\f$ A=B+C \f$).
703 // \ingroup dense_matrix
704 //
705 // \param lhs The left-hand side dense matrix for the addition.
706 // \param rhs The right-hand side zero matrix for the addition.
707 // \return Reference to the left-hand side dense matrix.
708 //
709 // This function implements a performance optimized treatment of the addition between a row-major
710 // dense matrix and a column-major zero matrix. It returns a reference to the left-hand side dense
711 // matrix.
712 */
713 template< typename MT1  // Type of the left-hand side dense matrix
714         , typename MT2  // Type of the right-hand side sparse matrix
715         , EnableIf_t< IsZero_v<MT2> &&
716                       IsSame_v< ElementType_t<MT1>, ElementType_t<MT2> > >* = nullptr >
717 inline const MT1&
dmattsmatadd(const DenseMatrix<MT1,false> & lhs,const SparseMatrix<MT2,true> & rhs)718    dmattsmatadd( const DenseMatrix<MT1,false>& lhs, const SparseMatrix<MT2,true>& rhs )
719 {
720    BLAZE_FUNCTION_TRACE;
721 
722    MAYBE_UNUSED( rhs );
723 
724    BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == (*rhs).rows()   , "Invalid number of rows"    );
725    BLAZE_INTERNAL_ASSERT( (*lhs).columns() == (*rhs).columns(), "Invalid number of columns" );
726 
727    return (*lhs);
728 }
729 /*! \endcond */
730 //*************************************************************************************************
731 
732 
733 //*************************************************************************************************
734 /*!\brief Addition operator for the addition of a row-major dense matrix and a column-major
735 //        sparse matrix (\f$ A=B+C \f$).
736 // \ingroup dense_matrix
737 //
738 // \param lhs The left-hand side dense matrix for the matrix addition.
739 // \param rhs The right-hand side sparse matrix to be added to the left-hand side matrix.
740 // \return The sum of the two matrices.
741 // \exception std::invalid_argument Matrix sizes do not match.
742 //
743 // This operator represents the addition of a row-major dense matrix and a column-major sparse
744 // matrix:
745 
746    \code
747    using blaze::rowMajor;
748    using blaze::columnMajor;
749 
750    blaze::DynamicMatrix<double,rowMajor> A, C;
751    blaze::CompressedMatrix<double,columnMajor> B;
752    // ... Resizing and initialization
753    C = A + B;
754    \endcode
755 
756 // The operator returns an expression representing a dense matrix of the higher-order element
757 // type of the two involved matrix element types \a MT1::ElementType and \a MT2::ElementType.
758 // Both matrix types \a MT1 and \a MT2 as well as the two element types \a MT1::ElementType
759 // and \a MT2::ElementType have to be supported by the AddTrait class template.\n
760 // In case the current sizes of the two given matrices don't match, a \a std::invalid_argument
761 // is thrown.
762 */
763 template< typename MT1    // Type of the left-hand side dense matrix
764         , typename MT2 >  // Type of the right-hand side sparse matrix
765 inline decltype(auto)
766    operator+( const DenseMatrix<MT1,false>& lhs, const SparseMatrix<MT2,true>& rhs )
767 {
768    BLAZE_FUNCTION_TRACE;
769 
770    if( (*lhs).rows() != (*rhs).rows() || (*lhs).columns() != (*rhs).columns() ) {
771       BLAZE_THROW_INVALID_ARGUMENT( "Matrix sizes do not match" );
772    }
773 
774    return dmattsmatadd( *lhs, *rhs );
775 }
776 //*************************************************************************************************
777 
778 
779 //*************************************************************************************************
780 /*!\brief Addition operator for the addition of a column-major sparse matrix and a row-major
781 //        dense matrix (\f$ A=B+C \f$).
782 // \ingroup dense_matrix
783 //
784 // \param lhs The left-hand side sparse matrix for the matrix addition.
785 // \param rhs The right-hand side dense matrix to be added to the left-hand side matrix.
786 // \return The sum of the two matrices.
787 // \exception std::invalid_argument Matrix sizes do not match.
788 //
789 // This operator represents the addition of a column-major sparse matrix and a row-major dense
790 // matrix:
791 
792    \code
793    using blaze::rowMajor;
794    using blaze::columnMajor;
795 
796    blaze::CompressedMatrix<double,columnMajor> A;
797    blaze::DynamicMatrix<double,rowMajor> B, C;
798    // ... Resizing and initialization
799    C = A + B;
800    \endcode
801 
802 // The operator returns an expression representing a dense matrix of the higher-order element
803 // type of the two involved matrix element types \a MT1::ElementType and \a MT2::ElementType.
804 // Both matrix types \a MT1 and \a MT2 as well as the two element types \a MT1::ElementType
805 // and \a MT2::ElementType have to be supported by the AddTrait class template.\n
806 // In case the current sizes of the two given matrices don't match, a \a std::invalid_argument
807 // is thrown.
808 */
809 template< typename MT1    // Type of the left-hand side sparse matrix
810         , typename MT2 >  // Type of the right-hand side dense matrix
811 inline decltype(auto)
812    operator+( const SparseMatrix<MT1,true>& lhs, const DenseMatrix<MT2,false>& rhs )
813 {
814    BLAZE_FUNCTION_TRACE;
815 
816    if( (*lhs).rows() != (*rhs).rows() || (*lhs).columns() != (*rhs).columns() ) {
817       BLAZE_THROW_INVALID_ARGUMENT( "Matrix sizes do not match" );
818    }
819 
820    return dmattsmatadd( *rhs, *lhs );
821 }
822 //*************************************************************************************************
823 
824 
825 
826 
827 //=================================================================================================
828 //
829 //  GLOBAL RESTRUCTURING BINARY ARITHMETIC OPERATORS
830 //
831 //=================================================================================================
832 
833 //*************************************************************************************************
834 /*! \cond BLAZE_INTERNAL */
835 /*!\brief Addition operator for the addition of a dense matrix-transpose sparse matrix
836 //        addition expression and a dense matrix (\f$ A=(B+C)+D \f$).
837 // \ingroup dense_matrix
838 //
839 // \param lhs The left-hand side dense matrix-transpose sparse matrix addition.
840 // \param rhs The right-hand side dense matrix.
841 // \return The sum of the two matrices.
842 //
843 // This operator implements a performance optimized treatment of the addition of a dense
844 // matrix-transpose sparse matrix addition expression to a dense matrix.
845 */
846 template< typename MT1  // Type of the dense matrix of the left-hand side expression
847         , typename MT2  // Type of the sparse matrix of the left-hand side expression
848         , typename MT3  // Type of the right-hand side dense matrix
849         , bool SO >     // Storage order of the right-hand side dense matrix
850 inline decltype(auto)
851    operator+( const DMatTSMatAddExpr<MT1,MT2>& lhs, const DenseMatrix<MT3,SO>& rhs )
852 {
853    BLAZE_FUNCTION_TRACE;
854 
855    return ( lhs.leftOperand() + (*rhs) ) + lhs.rightOperand();
856 }
857 /*! \endcond */
858 //*************************************************************************************************
859 
860 
861 //*************************************************************************************************
862 /*! \cond BLAZE_INTERNAL */
863 /*!\brief Subtraction operator for the subtraction of a dense matrix-transpose sparse matrix
864 //        addition expression and a dense matrix (\f$ A=(B+C)-D \f$).
865 // \ingroup dense_matrix
866 //
867 // \param lhs The left-hand side dense matrix-transpose sparse matrix addition.
868 // \param rhs The right-hand side dense matrix.
869 // \return The difference of the two matrices.
870 //
871 // This operator implements a performance optimized treatment of the subtraction of a dense
872 // matrix-transpose sparse matrix addition expression and a dense matrix.
873 */
874 template< typename MT1  // Type of the dense matrix of the left-hand side expression
875         , typename MT2  // Type of the sparse matrix of the left-hand side expression
876         , typename MT3  // Type of the right-hand side dense matrix
877         , bool SO >     // Storage order of the right-hand side dense matrix
878 inline decltype(auto)
879    operator-( const DMatTSMatAddExpr<MT1,MT2>& lhs, const DenseMatrix<MT3,SO>& rhs )
880 {
881    BLAZE_FUNCTION_TRACE;
882 
883    return ( lhs.leftOperand() - (*rhs) ) + lhs.rightOperand();
884 }
885 /*! \endcond */
886 //*************************************************************************************************
887 
888 } // namespace blaze
889 
890 #endif
891