1 //=================================================================================================
2 /*!
3 //  \file blaze/math/expressions/DMatDMatSchurExpr.h
4 //  \brief Header file for the dense matrix/dense matrix Schur product 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_DMATDMATSCHUREXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_DMATDMATSCHUREXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <iterator>
44 #include <utility>
45 #include <blaze/math/Aliases.h>
46 #include <blaze/math/constraints/DenseMatrix.h>
47 #include <blaze/math/constraints/Identity.h>
48 #include <blaze/math/constraints/RequiresEvaluation.h>
49 #include <blaze/math/constraints/SchurExpr.h>
50 #include <blaze/math/constraints/StorageOrder.h>
51 #include <blaze/math/constraints/Zero.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/SchurExpr.h>
57 #include <blaze/math/shims/Serial.h>
58 #include <blaze/math/SIMD.h>
59 #include <blaze/math/sparse/Forward.h>
60 #include <blaze/math/traits/SchurTrait.h>
61 #include <blaze/math/typetraits/HasSIMDMult.h>
62 #include <blaze/math/typetraits/IsAligned.h>
63 #include <blaze/math/typetraits/IsCommutative.h>
64 #include <blaze/math/typetraits/IsExpression.h>
65 #include <blaze/math/typetraits/IsLower.h>
66 #include <blaze/math/typetraits/IsOperation.h>
67 #include <blaze/math/typetraits/IsPadded.h>
68 #include <blaze/math/typetraits/IsStrictlyLower.h>
69 #include <blaze/math/typetraits/IsStrictlyUpper.h>
70 #include <blaze/math/typetraits/IsTemporary.h>
71 #include <blaze/math/typetraits/IsUniLower.h>
72 #include <blaze/math/typetraits/IsUniUpper.h>
73 #include <blaze/math/typetraits/IsUpper.h>
74 #include <blaze/math/typetraits/RequiresEvaluation.h>
75 #include <blaze/system/HostDevice.h>
76 #include <blaze/system/Inline.h>
77 #include <blaze/system/Thresholds.h>
78 #include <blaze/util/Assert.h>
79 #include <blaze/util/EnableIf.h>
80 #include <blaze/util/FunctionTrace.h>
81 #include <blaze/util/IntegralConstant.h>
82 #include <blaze/util/MaybeUnused.h>
83 #include <blaze/util/mpl/If.h>
84 #include <blaze/util/Types.h>
85 
86 
87 namespace blaze {
88 
89 //=================================================================================================
90 //
91 //  CLASS DMATDMATSCHUREXPR
92 //
93 //=================================================================================================
94 
95 //*************************************************************************************************
96 /*!\brief Expression object for dense matrix-dense matrix Schur products.
97 // \ingroup dense_matrix_expression
98 //
99 // The DMatDMatSchurExpr class represents the compile time expression for Schur products between
100 // dense matrices with identical storage order.
101 */
102 template< typename MT1  // Type of the left-hand side dense matrix
103         , typename MT2  // Type of the right-hand side dense matrix
104         , bool SO >     // Storage order
105 class DMatDMatSchurExpr
106    : public SchurExpr< DenseMatrix< DMatDMatSchurExpr<MT1,MT2,SO>, SO > >
107    , private Computation
108 {
109  private:
110    //**Type definitions****************************************************************************
111    using RT1 = ResultType_t<MT1>;     //!< Result type of the left-hand side dense matrix expression.
112    using RT2 = ResultType_t<MT2>;     //!< Result type of the right-hand side dense matrix expression.
113    using RN1 = ReturnType_t<MT1>;     //!< Return type of the left-hand side dense matrix expression.
114    using RN2 = ReturnType_t<MT2>;     //!< Return type of the right-hand side dense matrix expression.
115    using CT1 = CompositeType_t<MT1>;  //!< Composite type of the left-hand side dense matrix expression.
116    using CT2 = CompositeType_t<MT2>;  //!< Composite type of the right-hand side dense matrix expression.
117    using ET1 = ElementType_t<MT1>;    //!< Element type of the left-hand side dense matrix expression.
118    using ET2 = ElementType_t<MT2>;    //!< Element type of the right-hand side dense matrix expression.
119    //**********************************************************************************************
120 
121    //**Return type evaluation**********************************************************************
122    //! Compilation switch for the selection of the subscript operator return type.
123    /*! The \a returnExpr compile time constant expression is a compilation switch for the
124        selection of the \a ReturnType. If either matrix operand returns a temporary vector
125        or matrix, \a returnExpr will be set to \a false and the subscript operator will
126        return it's result by value. Otherwise \a returnExpr will be set to \a true and
127        the subscript operator may return it's result as an expression. */
128    static constexpr bool returnExpr = ( !IsTemporary_v<RN1> && !IsTemporary_v<RN2> );
129 
130    //! Expression return type for the subscript operator.
131    using ExprReturnType = decltype( std::declval<RN1>() * std::declval<RN2>() );
132    //**********************************************************************************************
133 
134    //**Serial evaluation strategy******************************************************************
135    //! Compilation switch for the serial evaluation strategy of the Schur product expression.
136    /*! The \a useAssign compile time constant expression represents a compilation switch for the
137        serial evaluation strategy of the Schur product expression. In case either of the two dense
138        matrix operands requires an intermediate evaluation or the subscript operator can only
139        return by value, \a useAssign will be set to 1 and the Schur product expression will be
140        evaluated via the \a assign function family. Otherwise \a useAssign will be set to 0 and
141        the expression will be evaluated via the function call operator. */
142    static constexpr bool useAssign =
143       ( RequiresEvaluation_v<MT1> || RequiresEvaluation_v<MT2> || !returnExpr );
144 
145    /*! \cond BLAZE_INTERNAL */
146    //! Helper variable template for the explicit application of the SFINAE principle.
147    template< typename MT >
148    static constexpr bool UseAssign_v = useAssign;
149    /*! \endcond */
150    //**********************************************************************************************
151 
152    //**Parallel evaluation strategy****************************************************************
153    /*! \cond BLAZE_INTERNAL */
154    //! Helper variable template for the explicit application of the SFINAE principle.
155    /*! This variable template is a helper for the selection of the parallel evaluation strategy.
156        In case at least one of the two matrix operands is not SMP assignable and at least one of
157        the two operands requires an intermediate evaluation, the variable is set to 1 and the
158        expression specific evaluation strategy is selected. Otherwise the variable is set to 0
159        and the default strategy is chosen. */
160    template< typename MT >
161    static constexpr bool UseSMPAssign_v =
162       ( ( !MT1::smpAssignable || !MT2::smpAssignable ) && useAssign );
163    /*! \endcond */
164    //**********************************************************************************************
165 
166  public:
167    //**Type definitions****************************************************************************
168    //! Type of this DMatDMatSchurExpr instance.
169    using This = DMatDMatSchurExpr<MT1,MT2,SO>;
170 
171    //! Base type of this DMatDMatSchurExpr instance.
172    using BaseType = SchurExpr< DenseMatrix<This,SO> >;
173 
174    using ResultType    = SchurTrait_t<RT1,RT2>;        //!< Result type for expression template evaluations.
175    using OppositeType  = OppositeType_t<ResultType>;   //!< Result type with opposite storage order for expression template evaluations.
176    using TransposeType = TransposeType_t<ResultType>;  //!< Transpose type for expression template evaluations.
177    using ElementType   = ElementType_t<ResultType>;    //!< Resulting element type.
178 
179    //! Return type for expression template evaluations.
180    using ReturnType = const If_t< returnExpr, ExprReturnType, ElementType >;
181 
182    //! Data type for composite expression templates.
183    using CompositeType = If_t< useAssign, const ResultType, const DMatDMatSchurExpr& >;
184 
185    //! Composite type of the left-hand side dense matrix expression.
186    using LeftOperand = If_t< IsExpression_v<MT1>, const MT1, const MT1& >;
187 
188    //! Composite type of the right-hand side dense matrix expression.
189    using RightOperand = If_t< IsExpression_v<MT2>, const MT2, const MT2& >;
190    //**********************************************************************************************
191 
192    //**ConstIterator class definition**************************************************************
193    /*!\brief Iterator over the elements of the dense matrix.
194    */
195    class ConstIterator
196    {
197     public:
198       //**Type definitions*************************************************************************
199       using IteratorCategory = std::random_access_iterator_tag;  //!< The iterator category.
200       using ValueType        = ElementType;                      //!< Type of the underlying elements.
201       using PointerType      = ElementType*;                     //!< Pointer return type.
202       using ReferenceType    = ElementType&;                     //!< Reference return type.
203       using DifferenceType   = ptrdiff_t;                        //!< Difference between two iterators.
204 
205       // STL iterator requirements
206       using iterator_category = IteratorCategory;  //!< The iterator category.
207       using value_type        = ValueType;         //!< Type of the underlying elements.
208       using pointer           = PointerType;       //!< Pointer return type.
209       using reference         = ReferenceType;     //!< Reference return type.
210       using difference_type   = DifferenceType;    //!< Difference between two iterators.
211 
212       //! ConstIterator type of the left-hand side dense matrix expression.
213       using LeftIteratorType = ConstIterator_t<MT1>;
214 
215       //! ConstIterator type of the right-hand side dense matrix expression.
216       using RightIteratorType = ConstIterator_t<MT2>;
217       //*******************************************************************************************
218 
219       //**Constructor******************************************************************************
220       /*!\brief Constructor for the ConstIterator class.
221       //
222       // \param left Iterator to the initial left-hand side element.
223       // \param right Iterator to the initial right-hand side element.
224       */
ConstIterator(LeftIteratorType left,RightIteratorType right)225       inline BLAZE_DEVICE_CALLABLE ConstIterator( LeftIteratorType left, RightIteratorType right )
226          : left_ ( left  )  // Iterator to the current left-hand side element
227          , right_( right )  // Iterator to the current right-hand side element
228       {}
229       //*******************************************************************************************
230 
231       //**Addition assignment operator*************************************************************
232       /*!\brief Addition assignment operator.
233       //
234       // \param inc The increment of the iterator.
235       // \return The incremented iterator.
236       */
237       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator+=( size_t inc ) {
238          left_  += inc;
239          right_ += inc;
240          return *this;
241       }
242       //*******************************************************************************************
243 
244       //**Subtraction assignment operator**********************************************************
245       /*!\brief Subtraction assignment operator.
246       //
247       // \param dec The decrement of the iterator.
248       // \return The decremented iterator.
249       */
250       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator-=( size_t dec ) {
251          left_  -= dec;
252          right_ -= dec;
253          return *this;
254       }
255       //*******************************************************************************************
256 
257       //**Prefix increment operator****************************************************************
258       /*!\brief Pre-increment operator.
259       //
260       // \return Reference to the incremented iterator.
261       */
262       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator++() {
263          ++left_;
264          ++right_;
265          return *this;
266       }
267       //*******************************************************************************************
268 
269       //**Postfix increment operator***************************************************************
270       /*!\brief Post-increment operator.
271       //
272       // \return The previous position of the iterator.
273       */
274       inline BLAZE_DEVICE_CALLABLE const ConstIterator operator++( int ) {
275          return ConstIterator( left_++, right_++ );
276       }
277       //*******************************************************************************************
278 
279       //**Prefix decrement operator****************************************************************
280       /*!\brief Pre-decrement operator.
281       //
282       // \return Reference to the decremented iterator.
283       */
284       inline BLAZE_DEVICE_CALLABLE ConstIterator& operator--() {
285          --left_;
286          --right_;
287          return *this;
288       }
289       //*******************************************************************************************
290 
291       //**Postfix decrement operator***************************************************************
292       /*!\brief Post-decrement operator.
293       //
294       // \return The previous position of the iterator.
295       */
296       inline BLAZE_DEVICE_CALLABLE const ConstIterator operator--( int ) {
297          return ConstIterator( left_--, right_-- );
298       }
299       //*******************************************************************************************
300 
301       //**Element access operator******************************************************************
302       /*!\brief Direct access to the element at the current iterator position.
303       //
304       // \return The resulting value.
305       */
306       inline ReturnType operator*() const {
307          return (*left_) * (*right_);
308       }
309       //*******************************************************************************************
310 
311       //**Load function****************************************************************************
312       /*!\brief Access to the SIMD elements of the matrix.
313       //
314       // \return The resulting SIMD element.
315       */
load()316       inline auto load() const noexcept {
317          return left_.load() * right_.load();
318       }
319       //*******************************************************************************************
320 
321       //**Equality operator************************************************************************
322       /*!\brief Equality comparison between two ConstIterator objects.
323       //
324       // \param rhs The right-hand side iterator.
325       // \return \a true if the iterators refer to the same element, \a false if not.
326       */
327       inline BLAZE_DEVICE_CALLABLE bool operator==( const ConstIterator& rhs ) const {
328          return left_ == rhs.left_;
329       }
330       //*******************************************************************************************
331 
332       //**Inequality operator**********************************************************************
333       /*!\brief Inequality comparison between two ConstIterator objects.
334       //
335       // \param rhs The right-hand side iterator.
336       // \return \a true if the iterators don't refer to the same element, \a false if they do.
337       */
338       inline BLAZE_DEVICE_CALLABLE bool operator!=( const ConstIterator& rhs ) const {
339          return left_ != rhs.left_;
340       }
341       //*******************************************************************************************
342 
343       //**Less-than operator***********************************************************************
344       /*!\brief Less-than comparison between two ConstIterator objects.
345       //
346       // \param rhs The right-hand side iterator.
347       // \return \a true if the left-hand side iterator is smaller, \a false if not.
348       */
349       inline BLAZE_DEVICE_CALLABLE bool operator<( const ConstIterator& rhs ) const {
350          return left_ < rhs.left_;
351       }
352       //*******************************************************************************************
353 
354       //**Greater-than operator********************************************************************
355       /*!\brief Greater-than comparison between two ConstIterator objects.
356       //
357       // \param rhs The right-hand side iterator.
358       // \return \a true if the left-hand side iterator is greater, \a false if not.
359       */
360       inline BLAZE_DEVICE_CALLABLE bool operator>( const ConstIterator& rhs ) const {
361          return left_ > rhs.left_;
362       }
363       //*******************************************************************************************
364 
365       //**Less-or-equal-than operator**************************************************************
366       /*!\brief Less-than comparison between two ConstIterator objects.
367       //
368       // \param rhs The right-hand side iterator.
369       // \return \a true if the left-hand side iterator is smaller or equal, \a false if not.
370       */
371       inline BLAZE_DEVICE_CALLABLE bool operator<=( const ConstIterator& rhs ) const {
372          return left_ <= rhs.left_;
373       }
374       //*******************************************************************************************
375 
376       //**Greater-or-equal-than operator***********************************************************
377       /*!\brief Greater-than comparison between two ConstIterator objects.
378       //
379       // \param rhs The right-hand side iterator.
380       // \return \a true if the left-hand side iterator is greater or equal, \a false if not.
381       */
382       inline BLAZE_DEVICE_CALLABLE bool operator>=( const ConstIterator& rhs ) const {
383          return left_ >= rhs.left_;
384       }
385       //*******************************************************************************************
386 
387       //**Subtraction operator*********************************************************************
388       /*!\brief Calculating the number of elements between two iterators.
389       //
390       // \param rhs The right-hand side iterator.
391       // \return The number of elements between the two iterators.
392       */
393       inline BLAZE_DEVICE_CALLABLE DifferenceType operator-( const ConstIterator& rhs ) const {
394          return left_ - rhs.left_;
395       }
396       //*******************************************************************************************
397 
398       //**Addition operator************************************************************************
399       /*!\brief Addition between a ConstIterator and an integral value.
400       //
401       // \param it The iterator to be incremented.
402       // \param inc The number of elements the iterator is incremented.
403       // \return The incremented iterator.
404       */
405       friend inline const ConstIterator operator+( const ConstIterator& it, size_t inc ) {
406          return ConstIterator( it.left_ + inc, it.right_ + inc );
407       }
408       //*******************************************************************************************
409 
410       //**Addition operator************************************************************************
411       /*!\brief Addition between an integral value and a ConstIterator.
412       //
413       // \param inc The number of elements the iterator is incremented.
414       // \param it The iterator to be incremented.
415       // \return The incremented iterator.
416       */
417       friend inline const ConstIterator operator+( size_t inc, const ConstIterator& it ) {
418          return ConstIterator( it.left_ + inc, it.right_ + inc );
419       }
420       //*******************************************************************************************
421 
422       //**Subtraction operator*********************************************************************
423       /*!\brief Subtraction between a ConstIterator and an integral value.
424       //
425       // \param it The iterator to be decremented.
426       // \param dec The number of elements the iterator is decremented.
427       // \return The decremented iterator.
428       */
429       friend inline BLAZE_DEVICE_CALLABLE const ConstIterator operator-( const ConstIterator& it, size_t dec ) {
430          return ConstIterator( it.left_ - dec, it.right_ - dec );
431       }
432       //*******************************************************************************************
433 
434     private:
435       //**Member variables*************************************************************************
436       LeftIteratorType  left_;   //!< Iterator to the current left-hand side element.
437       RightIteratorType right_;  //!< Iterator to the current right-hand side element.
438       //*******************************************************************************************
439    };
440    //**********************************************************************************************
441 
442    //**Compilation flags***************************************************************************
443    //! Compilation switch for the expression template evaluation strategy.
444    static constexpr bool simdEnabled =
445       ( MT1::simdEnabled && MT2::simdEnabled && HasSIMDMult_v<ET1,ET2> );
446 
447    //! Compilation switch for the expression template assignment strategy.
448    static constexpr bool smpAssignable = ( MT1::smpAssignable && MT2::smpAssignable );
449    //**********************************************************************************************
450 
451    //**SIMD properties*****************************************************************************
452    //! The number of elements packed within a single SIMD element.
453    static constexpr size_t SIMDSIZE = SIMDTrait<ElementType>::size;
454    //**********************************************************************************************
455 
456    //**Constructor*********************************************************************************
457    /*!\brief Constructor for the DMatDMatSchurExpr class.
458    //
459    // \param lhs The left-hand side operand of the Schur product expression.
460    // \param rhs The right-hand side operand of the Schur product expression.
461    */
DMatDMatSchurExpr(const MT1 & lhs,const MT2 & rhs)462    inline DMatDMatSchurExpr( const MT1& lhs, const MT2& rhs ) noexcept
463       : lhs_( lhs )  // Left-hand side dense matrix of the Schur product expression
464       , rhs_( rhs )  // Right-hand side dense matrix of the Schur product expression
465    {
466       BLAZE_INTERNAL_ASSERT( lhs.rows()    == rhs.rows()   , "Invalid number of rows"    );
467       BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.columns(), "Invalid number of columns" );
468    }
469    //**********************************************************************************************
470 
471    //**Access operator*****************************************************************************
472    /*!\brief 2D-access to the matrix elements.
473    //
474    // \param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$.
475    // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
476    // \return The resulting value.
477    */
operator()478    inline ReturnType operator()( size_t i, size_t j ) const {
479       BLAZE_INTERNAL_ASSERT( i < lhs_.rows()   , "Invalid row access index"    );
480       BLAZE_INTERNAL_ASSERT( j < lhs_.columns(), "Invalid column access index" );
481       return lhs_(i,j) * rhs_(i,j);
482    }
483    //**********************************************************************************************
484 
485    //**At function*********************************************************************************
486    /*!\brief Checked access to the matrix elements.
487    //
488    // \param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$.
489    // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
490    // \return The resulting value.
491    // \exception std::out_of_range Invalid matrix access index.
492    */
at(size_t i,size_t j)493    inline ReturnType at( size_t i, size_t j ) const {
494       if( i >= lhs_.rows() ) {
495          BLAZE_THROW_OUT_OF_RANGE( "Invalid row access index" );
496       }
497       if( j >= lhs_.columns() ) {
498          BLAZE_THROW_OUT_OF_RANGE( "Invalid column access index" );
499       }
500       return (*this)(i,j);
501    }
502    //**********************************************************************************************
503 
504    //**Load function*******************************************************************************
505    /*!\brief Access to the SIMD elements of the matrix.
506    //
507    // \param i Access index for the row. The index has to be in the range \f$[0..M-1]\f$.
508    // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
509    // \return Reference to the accessed values.
510    */
load(size_t i,size_t j)511    BLAZE_ALWAYS_INLINE auto load( size_t i, size_t j ) const noexcept {
512       BLAZE_INTERNAL_ASSERT( i < lhs_.rows()   , "Invalid row access index"    );
513       BLAZE_INTERNAL_ASSERT( j < lhs_.columns(), "Invalid column access index" );
514       BLAZE_INTERNAL_ASSERT( !SO || ( i % SIMDSIZE == 0UL ), "Invalid row access index"    );
515       BLAZE_INTERNAL_ASSERT( SO  || ( j % SIMDSIZE == 0UL ), "Invalid column access index" );
516       return lhs_.load(i,j) * rhs_.load(i,j);
517    }
518    //**********************************************************************************************
519 
520    //**Begin function******************************************************************************
521    /*!\brief Returns an iterator to the first non-zero element of row/column \a i.
522    //
523    // \param i The row/column index.
524    // \return Iterator to the first non-zero element of row/column \a i.
525    */
begin(size_t i)526    inline ConstIterator begin( size_t i ) const {
527       return ConstIterator( lhs_.begin(i), rhs_.begin(i) );
528    }
529    //**********************************************************************************************
530 
531    //**End function********************************************************************************
532    /*!\brief Returns an iterator just past the last non-zero element of row/column \a i.
533    //
534    // \param i The row/column index.
535    // \return Iterator just past the last non-zero element of row/column \a i.
536    */
end(size_t i)537    inline ConstIterator end( size_t i ) const {
538       return ConstIterator( lhs_.end(i), rhs_.end(i) );
539    }
540    //**********************************************************************************************
541 
542    //**Rows function*******************************************************************************
543    /*!\brief Returns the current number of rows of the matrix.
544    //
545    // \return The number of rows of the matrix.
546    */
rows()547    inline size_t rows() const noexcept {
548       return lhs_.rows();
549    }
550    //**********************************************************************************************
551 
552    //**Columns function****************************************************************************
553    /*!\brief Returns the current number of columns of the matrix.
554    //
555    // \return The number of columns of the matrix.
556    */
columns()557    inline size_t columns() const noexcept {
558       return lhs_.columns();
559    }
560    //**********************************************************************************************
561 
562    //**Left operand access*************************************************************************
563    /*!\brief Returns the left-hand side dense matrix operand.
564    //
565    // \return The left-hand side dense matrix operand.
566    */
leftOperand()567    inline LeftOperand leftOperand() const noexcept {
568       return lhs_;
569    }
570    //**********************************************************************************************
571 
572    //**Right operand access************************************************************************
573    /*!\brief Returns the right-hand side dense matrix operand.
574    //
575    // \return The right-hand side dense matrix operand.
576    */
rightOperand()577    inline RightOperand rightOperand() const noexcept {
578       return rhs_;
579    }
580    //**********************************************************************************************
581 
582    //**********************************************************************************************
583    /*!\brief Returns whether the expression can alias with the given address \a alias.
584    //
585    // \param alias The alias to be checked.
586    // \return \a true in case the expression can alias, \a false otherwise.
587    */
588    template< typename T >
canAlias(const T * alias)589    inline bool canAlias( const T* alias ) const noexcept {
590       return ( IsExpression_v<MT1> && ( RequiresEvaluation_v<MT1> ? lhs_.isAliased( alias ) : lhs_.canAlias( alias ) ) ) ||
591              ( IsExpression_v<MT2> && ( RequiresEvaluation_v<MT2> ? rhs_.isAliased( alias ) : rhs_.canAlias( alias ) ) );
592    }
593    //**********************************************************************************************
594 
595    //**********************************************************************************************
596    /*!\brief Returns whether the expression is aliased with the given address \a alias.
597    //
598    // \param alias The alias to be checked.
599    // \return \a true in case an alias effect is detected, \a false otherwise.
600    */
601    template< typename T >
isAliased(const T * alias)602    inline bool isAliased( const T* alias ) const noexcept {
603       return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
604    }
605    //**********************************************************************************************
606 
607    //**********************************************************************************************
608    /*!\brief Returns whether the operands of the expression are properly aligned in memory.
609    //
610    // \return \a true in case the operands are aligned, \a false if not.
611    */
isAligned()612    inline bool isAligned() const noexcept {
613       return lhs_.isAligned() && rhs_.isAligned();
614    }
615    //**********************************************************************************************
616 
617    //**********************************************************************************************
618    /*!\brief Returns whether the expression can be used in SMP assignments.
619    //
620    // \return \a true in case the expression can be used in SMP assignments, \a false if not.
621    */
canSMPAssign()622    inline bool canSMPAssign() const noexcept {
623       return lhs_.canSMPAssign() || rhs_.canSMPAssign() ||
624              ( rows() * columns() >= SMP_DMATDMATSCHUR_THRESHOLD );
625    }
626    //**********************************************************************************************
627 
628  private:
629    //**Member variables****************************************************************************
630    LeftOperand  lhs_;  //!< Left-hand side dense matrix of the Schur product expression.
631    RightOperand rhs_;  //!< Right-hand side dense matrix of the Schur product expression.
632    //**********************************************************************************************
633 
634    //**Assignment to dense matrices****************************************************************
635    /*! \cond BLAZE_INTERNAL */
636    /*!\brief Assignment of a non-commutative dense matrix-dense matrix Schur product to a
637    //        dense matrix.
638    // \ingroup dense_matrix
639    //
640    // \param lhs The target left-hand side dense matrix.
641    // \param rhs The right-hand side Schur product expression to be assigned.
642    // \return void
643    //
644    // This function implements the performance optimized assignment of a non-commutative dense
645    // matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
646    // application of the SFINAE principle, this function can only be selected by the compiler
647    // in case either of the two operands requires an intermediate evaluation.
648    */
649    template< typename MT  // Type of the target dense matrix
650            , bool SO2 >   // Storage order of the target dense matrix
651    friend inline auto assign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
652       -> EnableIf_t< UseAssign_v<MT> && !IsCommutative_v<MT1,MT2> >
653    {
654       BLAZE_FUNCTION_TRACE;
655 
656       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
657       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
658 
659       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
660          schurAssign( *lhs, rhs.rhs_ );
661       }
662       else {
663          CT1 A( serial( rhs.lhs_ ) );
664          CT2 B( serial( rhs.rhs_ ) );
665          assign( *lhs, A % B );
666       }
667    }
668    /*! \endcond */
669    //**********************************************************************************************
670 
671    //**Assignment to dense matrices****************************************************************
672    /*! \cond BLAZE_INTERNAL */
673    /*!\brief Assignment of a commutative dense matrix-dense matrix Schur product to a dense matrix.
674    // \ingroup dense_matrix
675    //
676    // \param lhs The target left-hand side dense matrix.
677    // \param rhs The right-hand side Schur product expression to be assigned.
678    // \return void
679    //
680    // This function implements the performance optimized assignment of a commutative dense
681    // matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
682    // application of the SFINAE principle, this function can only be selected by the compiler
683    // in case either of the two operands requires an intermediate evaluation.
684    */
685    template< typename MT  // Type of the target dense matrix
686            , bool SO2 >   // Storage order of the target dense matrix
687    friend inline auto assign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
688       -> EnableIf_t< UseAssign_v<MT> && IsCommutative_v<MT1,MT2> >
689    {
690       BLAZE_FUNCTION_TRACE;
691 
692       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
693       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
694 
695       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
696          schurAssign( *lhs, rhs.rhs_ );
697       }
698       else if( !IsOperation_v<MT2> && isSame( *lhs, rhs.rhs_ ) ) {
699          schurAssign( *lhs, rhs.lhs_ );
700       }
701       else if( !RequiresEvaluation_v<MT2> ) {
702          assign     ( *lhs, rhs.rhs_ );
703          schurAssign( *lhs, rhs.lhs_ );
704       }
705       else {
706          assign     ( *lhs, rhs.lhs_ );
707          schurAssign( *lhs, rhs.rhs_ );
708       }
709    }
710    /*! \endcond */
711    //**********************************************************************************************
712 
713    //**Assignment to sparse matrices***************************************************************
714    /*! \cond BLAZE_INTERNAL */
715    /*!\brief Assignment of a dense matrix-dense matrix Schur product to a sparse matrix.
716    // \ingroup dense_matrix
717    //
718    // \param lhs The target left-hand side sparse matrix.
719    // \param rhs The right-hand side Schur product expression to be assigned.
720    // \return void
721    //
722    // This function implements the performance optimized assignment of a dense matrix-dense
723    // matrix Schur product expression to a sparse matrix. Due to the explicit application of
724    // the SFINAE principle, this function can only be selected by the compiler in case either
725    // of the two operands requires an intermediate evaluation.
726    */
727    template< typename MT  // Type of the target sparse matrix
728            , bool SO2 >   // Storage order of the target sparse matrix
729    friend inline auto assign( SparseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
730       -> EnableIf_t< UseAssign_v<MT> >
731    {
732       BLAZE_FUNCTION_TRACE;
733 
734       using TmpType = If_t< SO == SO2, ResultType, OppositeType >;
735 
736       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
737       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( OppositeType );
738       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
739       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( OppositeType, !SO );
740       BLAZE_CONSTRAINT_MATRICES_MUST_HAVE_SAME_STORAGE_ORDER( MT, TmpType );
741       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( TmpType );
742 
743       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
744       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
745 
746       const TmpType tmp( serial( rhs ) );
747       assign( *lhs, tmp );
748    }
749    /*! \endcond */
750    //**********************************************************************************************
751 
752    //**Addition assignment to dense matrices*******************************************************
753    /*! \cond BLAZE_INTERNAL */
754    /*!\brief Addition assignment of a dense matrix-dense matrix Schur product to a dense matrix.
755    // \ingroup dense_matrix
756    //
757    // \param lhs The target left-hand side dense matrix.
758    // \param rhs The right-hand side Schur product expression to be added.
759    // \return void
760    //
761    // This function implements the performance optimized addition assignment of a dense matrix-
762    // dense matrix Schur product expression to a dense matrix. Due to the explicit application
763    // of the SFINAE principle, this function can only be selected by the compiler in case either
764    // of the operands requires an intermediate evaluation.
765    */
766    template< typename MT  // Type of the target dense matrix
767            , bool SO2 >   // Storage order of the target dense matrix
768    friend inline auto addAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
769       -> EnableIf_t< UseAssign_v<MT> >
770    {
771       BLAZE_FUNCTION_TRACE;
772 
773       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
774       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
775       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
776 
777       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
778       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
779 
780       const ResultType tmp( serial( rhs ) );
781       addAssign( *lhs, tmp );
782    }
783    /*! \endcond */
784    //**********************************************************************************************
785 
786    //**Addition assignment to sparse matrices******************************************************
787    // No special implementation for the addition assignment to sparse matrices.
788    //**********************************************************************************************
789 
790    //**Subtraction assignment to dense matrices****************************************************
791    /*! \cond BLAZE_INTERNAL */
792    /*!\brief Subtraction assignment of a dense matrix-dense matrix Schur product to a dense matrix.
793    // \ingroup dense_matrix
794    //
795    // \param lhs The target left-hand side dense matrix.
796    // \param rhs The right-hand side Schur product expression to be subtracted.
797    // \return void
798    //
799    // This function implements the performance optimized subtraction assignment of a dense matrix-
800    // dense matrix Schur product expression to a dense matrix. Due to the explicit application of
801    // the SFINAE principle, this function can only be selected by the compiler in case either
802    // of the operands requires an intermediate evaluation.
803    */
804    template< typename MT  // Type of the target dense matrix
805            , bool SO2 >   // Storage order of the target dense matrix
806    friend inline auto subAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
807       -> EnableIf_t< UseAssign_v<MT> >
808    {
809       BLAZE_FUNCTION_TRACE;
810 
811       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
812       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
813       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
814 
815       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
816       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
817 
818       const ResultType tmp( serial( rhs ) );
819       subAssign( *lhs, tmp );
820    }
821    /*! \endcond */
822    //**********************************************************************************************
823 
824    //**Subtraction assignment to sparse matrices***************************************************
825    // No special implementation for the subtraction assignment to sparse matrices.
826    //**********************************************************************************************
827 
828    //**Schur product assignment to dense matrices**************************************************
829    /*! \cond BLAZE_INTERNAL */
830    /*!\brief Schur product assignment of a non-commutative dense matrix-dense matrix Schur
831    //        product to a dense matrix.
832    // \ingroup dense_matrix
833    //
834    // \param lhs The target left-hand side dense matrix.
835    // \param rhs The right-hand side Schur product expression for the Schur product.
836    // \return void
837    //
838    // This function implements the performance optimized Schur product assignment of a
839    // non-commutative dense matrix-dense matrix Schur product expression to a dense matrix. Due
840    // to the explicit application of the SFINAE principle, this function can only be selected by
841    // the compiler in case either of the operands requires an intermediate evaluation.
842    */
843    template< typename MT  // Type of the target dense matrix
844            , bool SO2 >   // Storage order of the target dense matrix
845    friend inline auto schurAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
846       -> EnableIf_t< UseAssign_v<MT> && !IsCommutative_v<MT1,MT2> >
847    {
848       BLAZE_FUNCTION_TRACE;
849 
850       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
851       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
852       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
853 
854       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
855       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
856 
857       const ResultType tmp( serial( rhs ) );
858       schurAssign( *lhs, tmp );
859    }
860    /*! \endcond */
861    //**********************************************************************************************
862 
863    //**Schur product assignment to dense matrices**************************************************
864    /*! \cond BLAZE_INTERNAL */
865    /*!\brief Schur product assignment of a commutative dense matrix-dense matrix Schur product
866    //        to a dense matrix.
867    // \ingroup dense_matrix
868    //
869    // \param lhs The target left-hand side dense matrix.
870    // \param rhs The right-hand side Schur product expression for the Schur product.
871    // \return void
872    //
873    // This function implements the performance optimized Schur product assignment of a
874    // commutative dense matrix-dense matrix Schur product expression to a dense matrix. Due
875    // to the explicit application of the SFINAE principle, this function can only be selected
876    // by the compiler in case either of the operands requires an intermediate evaluation.
877    */
878    template< typename MT  // Type of the target dense matrix
879            , bool SO2 >   // Storage order of the target dense matrix
880    friend inline auto schurAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
881       -> EnableIf_t< UseAssign_v<MT> && IsCommutative_v<MT1,MT2> >
882    {
883       BLAZE_FUNCTION_TRACE;
884 
885       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
886       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
887 
888       if( !RequiresEvaluation_v<MT2> ) {
889          schurAssign( *lhs, rhs.rhs_ );
890          schurAssign( *lhs, rhs.lhs_ );
891       }
892       else {
893          schurAssign( *lhs, rhs.lhs_ );
894          schurAssign( *lhs, rhs.rhs_ );
895       }
896    }
897    /*! \endcond */
898    //**********************************************************************************************
899 
900    //**Schur product assignment to sparse matrices*************************************************
901    // No special implementation for the Schur product assignment to sparse matrices.
902    //**********************************************************************************************
903 
904    //**Multiplication assignment to dense matrices*************************************************
905    // No special implementation for the multiplication assignment to dense matrices.
906    //**********************************************************************************************
907 
908    //**Multiplication assignment to sparse matrices************************************************
909    // No special implementation for the multiplication assignment to sparse matrices.
910    //**********************************************************************************************
911 
912    //**SMP assignment to dense matrices************************************************************
913    /*! \cond BLAZE_INTERNAL */
914    /*!\brief SMP assignment of non-commutative a dense matrix-dense matrix Schur product to a
915    //        dense matrix.
916    // \ingroup dense_matrix
917    //
918    // \param lhs The target left-hand side dense matrix.
919    // \param rhs The right-hand side Schur product expression to be assigned.
920    // \return void
921    //
922    // This function implements the performance optimized SMP assignment of a non-commutative
923    // dense matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
924    // application of the SFINAE principle, this function can only be selected by the compiler
925    // in case the expression specific parallel evaluation strategy is selected.
926    */
927    template< typename MT  // Type of the target dense matrix
928            , bool SO2 >   // Storage order of the target dense matrix
929    friend inline auto smpAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
930       -> EnableIf_t< UseSMPAssign_v<MT> && !IsCommutative_v<MT1,MT2> >
931    {
932       BLAZE_FUNCTION_TRACE;
933 
934       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
935       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
936 
937       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
938          smpSchurAssign( *lhs, rhs.rhs_ );
939       }
940       else {
941          CT1 A( rhs.lhs_ );
942          CT2 B( rhs.rhs_ );
943          smpAssign( *lhs, A % B );
944       }
945    }
946    /*! \endcond */
947    //**********************************************************************************************
948 
949    //**SMP assignment to dense matrices************************************************************
950    /*! \cond BLAZE_INTERNAL */
951    /*!\brief SMP assignment of commutative a dense matrix-dense matrix Schur product to a
952    //        dense matrix.
953    // \ingroup dense_matrix
954    //
955    // \param lhs The target left-hand side dense matrix.
956    // \param rhs The right-hand side Schur product expression to be assigned.
957    // \return void
958    //
959    // This function implements the performance optimized SMP assignment of a commutative dense
960    // matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
961    // application of the SFINAE principle, this function can only be selected by the compiler
962    // in case the expression specific parallel evaluation strategy is selected.
963    */
964    template< typename MT  // Type of the target dense matrix
965            , bool SO2 >   // Storage order of the target dense matrix
966    friend inline auto smpAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
967       -> EnableIf_t< UseSMPAssign_v<MT> && IsCommutative_v<MT1,MT2> >
968    {
969       BLAZE_FUNCTION_TRACE;
970 
971       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
972       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
973 
974       if( !IsOperation_v<MT1> && isSame( *lhs, rhs.lhs_ ) ) {
975          smpSchurAssign( *lhs, rhs.rhs_ );
976       }
977       else if( !IsOperation_v<MT2> && isSame( *lhs, rhs.rhs_ ) ) {
978          smpSchurAssign( *lhs, rhs.lhs_ );
979       }
980       else if( !RequiresEvaluation_v<MT2> ) {
981          smpAssign     ( *lhs, rhs.rhs_ );
982          smpSchurAssign( *lhs, rhs.lhs_ );
983       }
984       else {
985          smpAssign     ( *lhs, rhs.lhs_ );
986          smpSchurAssign( *lhs, rhs.rhs_ );
987       }
988    }
989    /*! \endcond */
990    //**********************************************************************************************
991 
992    //**SMP assignment to sparse matrices***********************************************************
993    /*! \cond BLAZE_INTERNAL */
994    /*!\brief SMP assignment of a dense matrix-dense matrix Schur product to a sparse matrix.
995    // \ingroup dense_matrix
996    //
997    // \param lhs The target left-hand side sparse matrix.
998    // \param rhs The right-hand side Schur product expression to be assigned.
999    // \return void
1000    //
1001    // This function implements the performance optimized SMP assignment of a dense matrix-dense
1002    // matrix Schur product expression to a sparse matrix. Due to the explicit application of the
1003    // SFINAE principle, this function can only be selected by the compiler in case the expression
1004    // specific parallel evaluation strategy is selected.
1005    */
1006    template< typename MT  // Type of the target sparse matrix
1007            , bool SO2 >   // Storage order of the target sparse matrix
1008    friend inline auto smpAssign( SparseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
1009       -> EnableIf_t< UseSMPAssign_v<MT> >
1010    {
1011       BLAZE_FUNCTION_TRACE;
1012 
1013       using TmpType = If_t< SO == SO2, ResultType, OppositeType >;
1014 
1015       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
1016       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( OppositeType );
1017       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
1018       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( OppositeType, !SO );
1019       BLAZE_CONSTRAINT_MATRICES_MUST_HAVE_SAME_STORAGE_ORDER( MT, TmpType );
1020       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( TmpType );
1021 
1022       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
1023       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
1024 
1025       const TmpType tmp( rhs );
1026       smpAssign( *lhs, tmp );
1027    }
1028    /*! \endcond */
1029    //**********************************************************************************************
1030 
1031    //**SMP addition assignment to dense matrices***************************************************
1032    /*! \cond BLAZE_INTERNAL */
1033    /*!\brief SMP addition assignment of a dense matrix-dense matrix Schur product to a dense matrix.
1034    // \ingroup dense_matrix
1035    //
1036    // \param lhs The target left-hand side dense matrix.
1037    // \param rhs The right-hand side Schur product expression to be added.
1038    // \return void
1039    //
1040    // This function implements the performance optimized SMP addition assignment of a dense
1041    // matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
1042    // application of the SFINAE principle, this function can only be selected by the compiler
1043    // in case the expression specific parallel evaluation strategy is selected.
1044    */
1045    template< typename MT  // Type of the target dense matrix
1046            , bool SO2 >   // Storage order of the target dense matrix
1047    friend inline auto smpAddAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
1048       -> EnableIf_t< UseAssign_v<MT> >
1049    {
1050       BLAZE_FUNCTION_TRACE;
1051 
1052       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
1053       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
1054       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
1055 
1056       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
1057       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
1058 
1059       const ResultType tmp( rhs );
1060       smpAddAssign( *lhs, tmp );
1061    }
1062    /*! \endcond */
1063    //**********************************************************************************************
1064 
1065    //**SMP addition assignment to sparse matrices**************************************************
1066    // No special implementation for the SMP addition assignment to sparse matrices.
1067    //**********************************************************************************************
1068 
1069    //**SMP subtraction assignment to dense matrices************************************************
1070    /*! \cond BLAZE_INTERNAL */
1071    /*!\brief SMP subtraction assignment of a dense matrix-dense matrix Schur product to a
1072    //        dense matrix.
1073    // \ingroup dense_matrix
1074    //
1075    // \param lhs The target left-hand side dense matrix.
1076    // \param rhs The right-hand side Schur product expression to be subtracted.
1077    // \return void
1078    //
1079    // This function implements the performance optimized SMP subtraction assignment of a dense
1080    // matrix-dense matrix Schur product expression to a dense matrix. Due to the explicit
1081    // application of the SFINAE principle, this function can only be selected by the compiler
1082    // in case the expression specific parallel evaluation strategy is selected.
1083    */
1084    template< typename MT  // Type of the target dense matrix
1085            , bool SO2 >   // Storage order of the target dense matrix
1086    friend inline auto smpSubAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
1087       -> EnableIf_t< UseSMPAssign_v<MT> >
1088    {
1089       BLAZE_FUNCTION_TRACE;
1090 
1091       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
1092       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
1093       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
1094 
1095       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
1096       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
1097 
1098       const ResultType tmp( rhs );
1099       smpSubAssign( *lhs, tmp );
1100    }
1101    /*! \endcond */
1102    //**********************************************************************************************
1103 
1104    //**SMP subtraction assignment to sparse matrices***********************************************
1105    // No special implementation for the SMP subtraction assignment to sparse matrices.
1106    //**********************************************************************************************
1107 
1108    //**SMP Schur product assignment to dense matrices**********************************************
1109    /*! \cond BLAZE_INTERNAL */
1110    /*!\brief SMP Schur product assignment of a non-commutative dense matrix-dense matrix Schur
1111    //        product to a dense matrix.
1112    // \ingroup dense_matrix
1113    //
1114    // \param lhs The target left-hand side dense matrix.
1115    // \param rhs The right-hand side Schur product expression for the Schur product.
1116    // \return void
1117    //
1118    // This function implements the performance optimized SMP Schur product assignment of a
1119    // non-commutative dense matrix-dense matrix Schur product expression to a dense matrix. Due
1120    // to the explicit application of the SFINAE principle, this function can only be selected by
1121    // the compiler in case the expression specific parallel evaluation strategy is selected.
1122    */
1123    template< typename MT  // Type of the target dense matrix
1124            , bool SO2 >   // Storage order of the target dense matrix
1125    friend inline auto smpSchurAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
1126       -> EnableIf_t< UseSMPAssign_v<MT> && !IsCommutative_v<MT1,MT2> >
1127    {
1128       BLAZE_FUNCTION_TRACE;
1129 
1130       BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( ResultType );
1131       BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ResultType, SO );
1132       BLAZE_CONSTRAINT_MUST_NOT_REQUIRE_EVALUATION( ResultType );
1133 
1134       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
1135       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
1136 
1137       const ResultType tmp( rhs );
1138       smpSchurAssign( *lhs, tmp );
1139    }
1140    /*! \endcond */
1141    //**********************************************************************************************
1142 
1143    //**SMP Schur product assignment to dense matrices**********************************************
1144    /*! \cond BLAZE_INTERNAL */
1145    /*!\brief SMP Schur product assignment of a commutative dense matrix-dense matrix Schur
1146    //        product to a dense matrix.
1147    // \ingroup dense_matrix
1148    //
1149    // \param lhs The target left-hand side dense matrix.
1150    // \param rhs The right-hand side Schur product expression for the Schur product.
1151    // \return void
1152    //
1153    // This function implements the performance optimized SMP Schur product assignment of a
1154    // commutative dense matrix-dense matrix Schur product expression to a dense matrix. Due to
1155    // the explicit application of the SFINAE principle, this function can only be selected by
1156    // the compiler in case the expression specific parallel evaluation strategy is selected.
1157    */
1158    template< typename MT  // Type of the target dense matrix
1159            , bool SO2 >   // Storage order of the target dense matrix
1160    friend inline auto smpSchurAssign( DenseMatrix<MT,SO2>& lhs, const DMatDMatSchurExpr& rhs )
1161       -> EnableIf_t< UseSMPAssign_v<MT> && IsCommutative_v<MT1,MT2> >
1162    {
1163       BLAZE_FUNCTION_TRACE;
1164 
1165       BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == rhs.rows()   , "Invalid number of rows"    );
1166       BLAZE_INTERNAL_ASSERT( (*lhs).columns() == rhs.columns(), "Invalid number of columns" );
1167 
1168       if( !RequiresEvaluation_v<MT2> ) {
1169          smpSchurAssign( *lhs, rhs.rhs_ );
1170          smpSchurAssign( *lhs, rhs.lhs_ );
1171       }
1172       else {
1173          smpSchurAssign( *lhs, rhs.lhs_ );
1174          smpSchurAssign( *lhs, rhs.rhs_ );
1175       }
1176    }
1177    /*! \endcond */
1178    //**********************************************************************************************
1179 
1180    //**SMP Schur product assignment to sparse matrices*********************************************
1181    // No special implementation for the SMP Schur product assignment to sparse matrices.
1182    //**********************************************************************************************
1183 
1184    //**SMP multiplication assignment to dense matrices*********************************************
1185    // No special implementation for the SMP multiplication assignment to dense matrices.
1186    //**********************************************************************************************
1187 
1188    //**SMP multiplication assignment to sparse matrices********************************************
1189    // No special implementation for the SMP multiplication assignment to sparse matrices.
1190    //**********************************************************************************************
1191 
1192    //**Compile time checks*************************************************************************
1193    /*! \cond BLAZE_INTERNAL */
1194    BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( MT1 );
1195    BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE( MT2 );
1196    BLAZE_CONSTRAINT_MUST_FORM_VALID_SCHUREXPR( MT1, MT2 );
1197    /*! \endcond */
1198    //**********************************************************************************************
1199 };
1200 //*************************************************************************************************
1201 
1202 
1203 
1204 
1205 //=================================================================================================
1206 //
1207 //  GLOBAL BINARY ARITHMETIC OPERATORS
1208 //
1209 //=================================================================================================
1210 
1211 //*************************************************************************************************
1212 /*! \cond BLAZE_INTERNAL */
1213 /*!\brief Backend implementation of the Schur product between two dense matrices with identical
1214 //        storage order (\f$ A=B \circ C \f$).
1215 // \ingroup dense_matrix
1216 //
1217 // \param lhs The left-hand side dense matrix for the Schur product.
1218 // \param rhs The right-hand side dense matrix for the Schur product.
1219 // \return The Schur product of the two matrices.
1220 //
1221 // This function implements a performance optimized treatment of the Schur product of two
1222 // dense matrices with identical storage order.
1223 */
1224 template< typename MT1  // Type of the left-hand side dense matrix
1225         , typename MT2  // Type of the right-hand side dense matrix
1226         , bool SO       // Storage order
1227         , DisableIf_t< ( IsUniLower_v<MT1> && IsUniUpper_v<MT2> ) ||
1228                        ( IsUniUpper_v<MT1> && IsUniLower_v<MT2> ) ||
1229                        ( IsStrictlyLower_v<MT1> && IsUpper_v<MT2> ) ||
1230                        ( IsStrictlyUpper_v<MT1> && IsLower_v<MT2> ) ||
1231                        ( IsLower_v<MT1> && IsStrictlyUpper_v<MT2> ) ||
1232                        ( IsUpper_v<MT1> && IsStrictlyLower_v<MT2> ) >* = nullptr >
1233 inline const DMatDMatSchurExpr<MT1,MT2,SO>
dmatdmatschur(const DenseMatrix<MT1,SO> & lhs,const DenseMatrix<MT2,SO> & rhs)1234    dmatdmatschur( const DenseMatrix<MT1,SO>& lhs, const DenseMatrix<MT2,SO>& rhs )
1235 {
1236    BLAZE_FUNCTION_TRACE;
1237 
1238    BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == (*rhs).rows()   , "Invalid number of rows"    );
1239    BLAZE_INTERNAL_ASSERT( (*lhs).columns() == (*rhs).columns(), "Invalid number of columns" );
1240 
1241    return DMatDMatSchurExpr<MT1,MT2,SO>( *lhs, *rhs );
1242 }
1243 /*! \endcond */
1244 //*************************************************************************************************
1245 
1246 
1247 //*************************************************************************************************
1248 /*! \cond BLAZE_INTERNAL */
1249 /*!\brief Backend implementation of the Schur product between two unitriangular dense matrices
1250 //        with identical storage order (\f$ A=B \circ C \f$).
1251 // \ingroup dense_matrix
1252 //
1253 // \param lhs The left-hand side dense matrix for the Schur product.
1254 // \param rhs The right-hand side dense matrix for the Schur product.
1255 // \return The resulting identity matrix.
1256 //
1257 // This function implements a performance optimized treatment of the Schur product between two
1258 // unitriangular dense matrices with identical storage order. It returns an identity matrix.
1259 */
1260 template< typename MT1  // Type of the left-hand side dense matrix
1261         , typename MT2  // Type of the right-hand side dense matrix
1262         , bool SO       // Storage order
1263         , EnableIf_t< ( IsUniLower_v<MT1> && IsUniUpper_v<MT2> ) ||
1264                       ( IsUniUpper_v<MT1> && IsUniLower_v<MT2> ) >* = nullptr >
decltype(auto)1265 inline decltype(auto)
1266    dmatdmatschur( const DenseMatrix<MT1,SO>& lhs, const DenseMatrix<MT2,SO>& rhs )
1267 {
1268    BLAZE_FUNCTION_TRACE;
1269 
1270    MAYBE_UNUSED( rhs );
1271 
1272    BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == (*rhs).rows()   , "Invalid number of rows"    );
1273    BLAZE_INTERNAL_ASSERT( (*lhs).columns() == (*rhs).columns(), "Invalid number of columns" );
1274 
1275    using ReturnType = const SchurTrait_t< ResultType_t<MT1>, ResultType_t<MT2> >;
1276 
1277    BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ReturnType, SO );
1278    BLAZE_CONSTRAINT_MUST_BE_IDENTITY_MATRIX_TYPE( ReturnType );
1279 
1280    return ReturnType( (*lhs).rows() );
1281 }
1282 /*! \endcond */
1283 //*************************************************************************************************
1284 
1285 
1286 //*************************************************************************************************
1287 /*! \cond BLAZE_INTERNAL */
1288 /*!\brief Backend implementation of the Schur product between two (strictly) triangular dense
1289 //        matrices with identical storage order (\f$ A=B \circ C \f$).
1290 // \ingroup dense_matrix
1291 //
1292 // \param lhs The left-hand side dense matrix for the Schur product.
1293 // \param rhs The right-hand side dense matrix for the Schur product.
1294 // \return The resulting zero matrix.
1295 //
1296 // This function implements a performance optimized treatment of the Schur product between two
1297 // (strictly) triangular dense matrices with identical storage order. It returns a zero matrix.
1298 */
1299 template< typename MT1  // Type of the left-hand side dense matrix
1300         , typename MT2  // Type of the right-hand side dense matrix
1301         , bool SO       // Storage order
1302         , EnableIf_t< ( IsStrictlyLower_v<MT1> && IsUpper_v<MT2> ) ||
1303                       ( IsStrictlyUpper_v<MT1> && IsLower_v<MT2> ) ||
1304                       ( IsLower_v<MT1> && IsStrictlyUpper_v<MT2> ) ||
1305                       ( IsUpper_v<MT1> && IsStrictlyLower_v<MT2> ) >* = nullptr >
decltype(auto)1306 inline decltype(auto)
1307    dmatdmatschur( const DenseMatrix<MT1,SO>& lhs, const DenseMatrix<MT2,SO>& rhs )
1308 {
1309    BLAZE_FUNCTION_TRACE;
1310 
1311    MAYBE_UNUSED( rhs );
1312 
1313    BLAZE_INTERNAL_ASSERT( (*lhs).rows()    == (*rhs).rows()   , "Invalid number of rows"    );
1314    BLAZE_INTERNAL_ASSERT( (*lhs).columns() == (*rhs).columns(), "Invalid number of columns" );
1315 
1316    using ReturnType = const SchurTrait_t< ResultType_t<MT1>, ResultType_t<MT2> >;
1317 
1318    BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( ReturnType, SO );
1319    BLAZE_CONSTRAINT_MUST_BE_ZERO_TYPE( ReturnType );
1320 
1321    return ReturnType( (*lhs).rows(), (*lhs).columns() );
1322 }
1323 /*! \endcond */
1324 //*************************************************************************************************
1325 
1326 
1327 //*************************************************************************************************
1328 /*!\brief Operator for the Schur product of two dense matrices with identical storage order
1329 //        (\f$ A=B \circ C \f$).
1330 // \ingroup dense_matrix
1331 //
1332 // \param lhs The left-hand side dense matrix for the Schur product.
1333 // \param rhs The right-hand side dense matrix for the Schur product.
1334 // \return The Schur product of the two matrices.
1335 // \exception std::invalid_argument Matrix sizes do not match.
1336 //
1337 // This operator represents the Schur product of two dense matrices with identical storage order:
1338 
1339    \code
1340    blaze::DynamicMatrix<double> A, B, C;
1341    // ... Resizing and initialization
1342    C = A % B;
1343    \endcode
1344 
1345 // The operator returns an expression representing a dense matrix of the higher-order element
1346 // type of the two involved matrix element types \a MT1::ElementType and \a MT2::ElementType.
1347 // Both matrix types \a MT1 and \a MT2 as well as the two element types \a MT1::ElementType
1348 // and \a MT2::ElementType have to be supported by the MultTrait class template.\n
1349 // In case the current number of rows and columns of the two given  matrices don't match, a
1350 // \a std::invalid_argument is thrown.
1351 */
1352 template< typename MT1  // Type of the left-hand side dense matrix
1353         , typename MT2  // Type of the right-hand side dense matrix
1354         , bool SO >     // Storage order
1355 inline decltype(auto)
1356    operator%( const DenseMatrix<MT1,SO>& lhs, const DenseMatrix<MT2,SO>& rhs )
1357 {
1358    BLAZE_FUNCTION_TRACE;
1359 
1360    if( (*lhs).rows() != (*rhs).rows() || (*lhs).columns() != (*rhs).columns() ) {
1361       BLAZE_THROW_INVALID_ARGUMENT( "Matrix sizes do not match" );
1362    }
1363 
1364    return dmatdmatschur( *lhs, *rhs );
1365 }
1366 //*************************************************************************************************
1367 
1368 
1369 
1370 
1371 //=================================================================================================
1372 //
1373 //  ISALIGNED SPECIALIZATIONS
1374 //
1375 //=================================================================================================
1376 
1377 //*************************************************************************************************
1378 /*! \cond BLAZE_INTERNAL */
1379 template< typename MT1, typename MT2, bool SO >
1380 struct IsAligned< DMatDMatSchurExpr<MT1,MT2,SO> >
1381    : public BoolConstant< IsAligned_v<MT1> && IsAligned_v<MT2> >
1382 {};
1383 /*! \endcond */
1384 //*************************************************************************************************
1385 
1386 
1387 
1388 
1389 //=================================================================================================
1390 //
1391 //  ISPADDED SPECIALIZATIONS
1392 //
1393 //=================================================================================================
1394 
1395 //*************************************************************************************************
1396 /*! \cond BLAZE_INTERNAL */
1397 template< typename MT1, typename MT2, bool SO >
1398 struct IsPadded< DMatDMatSchurExpr<MT1,MT2,SO> >
1399    : public BoolConstant< IsPadded_v<MT1> && IsPadded_v<MT2> >
1400 {};
1401 /*! \endcond */
1402 //*************************************************************************************************
1403 
1404 } // namespace blaze
1405 
1406 #endif
1407