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