1 //=================================================================================================
2 /*!
3 //  \file blaze/math/adaptors/symmetricmatrix/DenseNonScalar.h
4 //  \brief SymmetricMatrix specialization for dense matrices with non-scalar element type
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_ADAPTORS_SYMMETRICMATRIX_DENSENONSCALAR_H_
36 #define _BLAZE_MATH_ADAPTORS_SYMMETRICMATRIX_DENSENONSCALAR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <iterator>
44 #include <utility>
45 #include <blaze/math/adaptors/symmetricmatrix/BaseTemplate.h>
46 #include <blaze/math/Aliases.h>
47 #include <blaze/math/constraints/Computation.h>
48 #include <blaze/math/constraints/DenseMatrix.h>
49 #include <blaze/math/constraints/Hermitian.h>
50 #include <blaze/math/constraints/Lower.h>
51 #include <blaze/math/constraints/Resizable.h>
52 #include <blaze/math/constraints/Scalar.h>
53 #include <blaze/math/constraints/StorageOrder.h>
54 #include <blaze/math/constraints/Symmetric.h>
55 #include <blaze/math/constraints/Transformation.h>
56 #include <blaze/math/constraints/Upper.h>
57 #include <blaze/math/constraints/View.h>
58 #include <blaze/math/dense/DenseMatrix.h>
59 #include <blaze/math/Exception.h>
60 #include <blaze/math/expressions/DenseMatrix.h>
61 #include <blaze/math/expressions/Forward.h>
62 #include <blaze/math/RelaxationFlag.h>
63 #include <blaze/math/shims/Clear.h>
64 #include <blaze/math/shims/Conjugate.h>
65 #include <blaze/math/shims/IsDefault.h>
66 #include <blaze/math/shims/IsZero.h>
67 #include <blaze/math/typetraits/IsComputation.h>
68 #include <blaze/math/typetraits/IsCustom.h>
69 #include <blaze/math/typetraits/IsScalar.h>
70 #include <blaze/math/typetraits/IsSMPAssignable.h>
71 #include <blaze/math/typetraits/IsSparseMatrix.h>
72 #include <blaze/math/typetraits/IsSquare.h>
73 #include <blaze/math/typetraits/IsSymmetric.h>
74 #include <blaze/math/typetraits/RemoveAdaptor.h>
75 #include <blaze/math/typetraits/Size.h>
76 #include <blaze/math/views/Submatrix.h>
77 #include <blaze/util/Assert.h>
78 #include <blaze/util/constraints/Const.h>
79 #include <blaze/util/constraints/Pointer.h>
80 #include <blaze/util/constraints/Reference.h>
81 #include <blaze/util/constraints/Volatile.h>
82 #include <blaze/util/EnableIf.h>
83 #include <blaze/util/MaybeUnused.h>
84 #include <blaze/util/mpl/If.h>
85 #include <blaze/util/StaticAssert.h>
86 #include <blaze/util/Types.h>
87 #include <blaze/util/typetraits/RemoveReference.h>
88 
89 
90 namespace blaze {
91 
92 //=================================================================================================
93 //
94 //  CLASS TEMPLATE SPECIALIZATION FOR DENSE MATRICES WITH NON-SCALAR ELEMENT TYPE
95 //
96 //=================================================================================================
97 
98 //*************************************************************************************************
99 /*! \cond BLAZE_INTERNAL */
100 /*!\brief Specialization of SymmetricMatrix for dense matrices with non-scalar element type.
101 // \ingroup symmetric_matrix
102 //
103 // This specialization of SymmetricMatrix adapts the class template to the requirements of dense
104 // matrices with non-scalar data type.
105 */
106 template< typename MT  // Type of the adapted dense matrix
107         , bool SO >    // Storage order of the adapted dense matrix
108 class SymmetricMatrix<MT,SO,true,false>
109    : public DenseMatrix< SymmetricMatrix<MT,SO,true,false>, SO >
110 {
111  private:
112    //**Type definitions****************************************************************************
113    using OT = OppositeType_t<MT>;   //!< Opposite type of the dense matrix.
114    using TT = TransposeType_t<MT>;  //!< Transpose type of the dense matrix.
115    using ET = ElementType_t<MT>;    //!< Element type of the dense matrix.
116    //**********************************************************************************************
117 
118  public:
119    //**Type definitions****************************************************************************
120    using This           = SymmetricMatrix<MT,SO,true,false>;   //!< Type of this SymmetricMatrix instance.
121    using BaseType       = DenseMatrix<This,SO>;                //!< Base type of this SymmetricMatrix instance.
122    using ResultType     = This;                                //!< Result type for expression template evaluations.
123    using OppositeType   = SymmetricMatrix<OT,!SO,true,false>;  //!< Result type with opposite storage order for expression template evaluations.
124    using TransposeType  = SymmetricMatrix<TT,!SO,true,false>;  //!< Transpose type for expression template evaluations.
125    using ElementType    = ET;                                  //!< Type of the matrix elements.
126    using TagType        = TagType_t<MT>;                       //!< Tag type of this SymmetricMatrix instance.
127    using ReturnType     = ReturnType_t<MT>;                    //!< Return type for expression template evaluations.
128    using CompositeType  = const This&;                         //!< Data type for composite expression templates.
129    using Reference      = Reference_t<MT>;                     //!< Reference to a non-constant matrix value.
130    using ConstReference = ConstReference_t<MT>;                //!< Reference to a constant matrix value.
131    using Pointer        = Pointer_t<MT>;                       //!< Pointer to a non-constant matrix value.
132    using ConstPointer   = ConstPointer_t<MT>;                  //!< Pointer to a constant matrix value.
133    //**********************************************************************************************
134 
135    //**Rebind struct definition********************************************************************
136    /*!\brief Rebind mechanism to obtain a SymmetricMatrix with different data/element type.
137    */
138    template< typename NewType >  // Data type of the other matrix
139    struct Rebind {
140       //! The type of the other SymmetricMatrix.
141       using Other = SymmetricMatrix< typename MT::template Rebind<NewType>::Other >;
142    };
143    //**********************************************************************************************
144 
145    //**Resize struct definition********************************************************************
146    /*!\brief Resize mechanism to obtain a SymmetricMatrix with different fixed dimensions.
147    */
148    template< size_t NewM    // Number of rows of the other matrix
149            , size_t NewN >  // Number of columns of the other matrix
150    struct Resize {
151       //! The type of the other SymmetricMatrix.
152       using Other = SymmetricMatrix< typename MT::template Resize<NewM,NewN>::Other >;
153    };
154    //**********************************************************************************************
155 
156    //**MatrixIterator class definition*************************************************************
157    /*!\brief Iterator over the elements of the dense symmetric matrix.
158    */
159    template< typename MatrixType >  // Type of the adapted dense matrix
160    class MatrixIterator
161    {
162     public:
163       //**Type definitions*************************************************************************
164       //! Return type for the access to the value of a dense matrix element.
165       using Reference = If_t< IsConst_v<MatrixType>
166                             , ConstReference_t<MatrixType>
167                             , Reference_t<MatrixType> >;
168 
169       using IteratorCategory = std::random_access_iterator_tag;  //!< The iterator category.
170       using ValueType        = RemoveReference_t<Reference>;     //!< Type of the underlying elements.
171       using PointerType      = ValueType*;                       //!< Pointer return type.
172       using ReferenceType    = Reference;                        //!< Reference return type.
173       using DifferenceType   = ptrdiff_t;                        //!< Difference between two iterators.
174 
175       // STL iterator requirements
176       using iterator_category = IteratorCategory;  //!< The iterator category.
177       using value_type        = ValueType;         //!< Type of the underlying elements.
178       using pointer           = PointerType;       //!< Pointer return type.
179       using reference         = ReferenceType;     //!< Reference return type.
180       using difference_type   = DifferenceType;    //!< Difference between two iterators.
181       //*******************************************************************************************
182 
183       //**Constructor******************************************************************************
184       /*!\brief Default constructor of the MatrixIterator class.
185       */
MatrixIterator()186       inline MatrixIterator() noexcept
187          : matrix_( nullptr )  // Reference to the adapted dense matrix
188          , row_   ( 0UL )      // The current row index of the iterator
189          , column_( 0UL )      // The current column index of the iterator
190       {}
191       //*******************************************************************************************
192 
193       //**Constructor******************************************************************************
194       /*!\brief Constructor for the MatrixIterator class.
195       //
196       // \param matrix The adapted matrix.
197       // \param row Initial row index of the iterator.
198       // \param column Initial column index of the iterator.
199       */
MatrixIterator(MatrixType & matrix,size_t row,size_t column)200       inline MatrixIterator( MatrixType& matrix, size_t row, size_t column ) noexcept
201          : matrix_( &matrix )  // Reference to the adapted dense matrix
202          , row_   ( row     )  // The current row index of the iterator
203          , column_( column  )  // The current column index of the iterator
204       {}
205       //*******************************************************************************************
206 
207       //**Conversion constructor*******************************************************************
208       /*!\brief Conversion constructor from different MatrixIterator instances.
209       //
210       // \param it The row iterator to be copied.
211       */
212       template< typename MatrixType2 >
MatrixIterator(const MatrixIterator<MatrixType2> & it)213       inline MatrixIterator( const MatrixIterator<MatrixType2>& it ) noexcept
214          : matrix_( it.matrix_ )  // Reference to the adapted dense matrix
215          , row_   ( it.row_    )  // The current row index of the iterator
216          , column_( it.column_ )  // The current column index of the iterator
217       {}
218       //*******************************************************************************************
219 
220       //**Addition assignment operator*************************************************************
221       /*!\brief Addition assignment operator.
222       //
223       // \param inc The increment of the iterator.
224       // \return The incremented iterator.
225       */
226       inline MatrixIterator& operator+=( size_t inc ) noexcept {
227          ( SO )?( row_ += inc ):( column_ += inc );
228          return *this;
229       }
230       //*******************************************************************************************
231 
232       //**Subtraction assignment operator**********************************************************
233       /*!\brief Subtraction assignment operator.
234       //
235       // \param dec The decrement of the iterator.
236       // \return The decremented iterator.
237       */
238       inline MatrixIterator& operator-=( size_t dec ) noexcept {
239          ( SO )?( row_ -= dec ):( column_ -= dec );
240          return *this;
241       }
242       //*******************************************************************************************
243 
244       //**Prefix increment operator****************************************************************
245       /*!\brief Pre-increment operator.
246       //
247       // \return Reference to the incremented iterator.
248       */
249       inline MatrixIterator& operator++() noexcept {
250          ( SO )?( ++row_ ):( ++column_ );
251          return *this;
252       }
253       //*******************************************************************************************
254 
255       //**Postfix increment operator***************************************************************
256       /*!\brief Post-increment operator.
257       //
258       // \return The previous position of the iterator.
259       */
260       inline const MatrixIterator operator++( int ) noexcept {
261          const MatrixIterator tmp( *this );
262          ++(*this);
263          return tmp;
264       }
265       //*******************************************************************************************
266 
267       //**Prefix decrement operator****************************************************************
268       /*!\brief Pre-decrement operator.
269       //
270       // \return Reference to the decremented iterator.
271       */
272       inline MatrixIterator& operator--() noexcept {
273          ( SO )?( --row_ ):( --column_ );
274          return *this;
275       }
276       //*******************************************************************************************
277 
278       //**Postfix decrement operator***************************************************************
279       /*!\brief Post-decrement operator.
280       //
281       // \return The previous position of the iterator.
282       */
283       inline const MatrixIterator operator--( int ) noexcept {
284          const MatrixIterator tmp( *this );
285          --(*this);
286          return tmp;
287       }
288       //*******************************************************************************************
289 
290       //**Element access operator******************************************************************
291       /*!\brief Direct access to the element at the current iterator position.
292       //
293       // \return The resulting value.
294       */
295       inline ReferenceType operator*() const {
296          if( ( SO && row_ < column_ ) || ( !SO && row_ > column_ ) )
297             return (*matrix_)(row_,column_);
298          else
299             return (*matrix_)(column_,row_);
300       }
301       //*******************************************************************************************
302 
303       //**Element access operator******************************************************************
304       /*!\brief Direct access to the element at the current iterator position.
305       //
306       // \return The resulting value.
307       */
308       inline PointerType operator->() const {
309          if( ( SO && row_ < column_ ) || ( !SO && row_ > column_ ) )
310             return &(*matrix_)(row_,column_);
311          else
312             return &(*matrix_)(column_,row_);
313       }
314       //*******************************************************************************************
315 
316       //**Equality operator************************************************************************
317       /*!\brief Equality comparison between two MatrixIterator objects.
318       //
319       // \param rhs The right-hand side iterator.
320       // \return \a true if the iterators refer to the same element, \a false if not.
321       */
322       template< typename MatrixType2 >
323       inline bool operator==( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
324          return ( SO )?( row_ == rhs.row_ ):( column_ == rhs.column_ );
325       }
326       //*******************************************************************************************
327 
328       //**Inequality operator**********************************************************************
329       /*!\brief Inequality comparison between two MatrixIterator objects.
330       //
331       // \param rhs The right-hand side iterator.
332       // \return \a true if the iterators don't refer to the same element, \a false if they do.
333       */
334       template< typename MatrixType2 >
335       inline bool operator!=( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
336          return ( SO )?( row_ != rhs.row_ ):( column_ != rhs.column_ );
337       }
338       //*******************************************************************************************
339 
340       //**Less-than operator***********************************************************************
341       /*!\brief Less-than comparison between two MatrixIterator objects.
342       //
343       // \param rhs The right-hand side iterator.
344       // \return \a true if the left-hand side iterator is smaller, \a false if not.
345       */
346       template< typename MatrixType2 >
347       inline bool operator<( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
348          return ( SO )?( row_ < rhs.row_ ):( column_ < rhs.column_ );
349          return ( column_ < rhs.column_ );
350       }
351       //*******************************************************************************************
352 
353       //**Greater-than operator********************************************************************
354       /*!\brief Greater-than comparison between two MatrixIterator objects.
355       //
356       // \param rhs The right-hand side iterator.
357       // \return \a true if the left-hand side iterator is greater, \a false if not.
358       */
359       template< typename MatrixType2 >
360       inline bool operator>( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
361          return ( SO )?( row_ > rhs.row_ ):( column_ > rhs.column_ );
362          return ( column_ > rhs.column_ );
363       }
364       //*******************************************************************************************
365 
366       //**Less-or-equal-than operator**************************************************************
367       /*!\brief Less-than comparison between two MatrixIterator objects.
368       //
369       // \param rhs The right-hand side iterator.
370       // \return \a true if the left-hand side iterator is smaller or equal, \a false if not.
371       */
372       template< typename MatrixType2 >
373       inline bool operator<=( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
374          return ( SO )?( row_ <= rhs.row_ ):( column_ <= rhs.column_ );
375       }
376       //*******************************************************************************************
377 
378       //**Greater-or-equal-than operator***********************************************************
379       /*!\brief Greater-than comparison between two MatrixIterator objects.
380       //
381       // \param rhs The right-hand side iterator.
382       // \return \a true if the left-hand side iterator is greater or equal, \a false if not.
383       */
384       template< typename MatrixType2 >
385       inline bool operator>=( const MatrixIterator<MatrixType2>& rhs ) const noexcept {
386          return ( SO )?( row_ >= rhs.row_ ):( column_ >= rhs.column_ );
387       }
388       //*******************************************************************************************
389 
390       //**Subtraction operator*********************************************************************
391       /*!\brief Calculating the number of elements between two iterators.
392       //
393       // \param rhs The right-hand side iterator.
394       // \return The number of elements between the two iterators.
395       */
396       inline DifferenceType operator-( const MatrixIterator& rhs ) const noexcept {
397          return ( SO )?( row_ - rhs.row_ ):( column_ - rhs.column_ );
398       }
399       //*******************************************************************************************
400 
401       //**Addition operator************************************************************************
402       /*!\brief Addition between a MatrixIterator and an integral value.
403       //
404       // \param it The iterator to be incremented.
405       // \param inc The number of elements the iterator is incremented.
406       // \return The incremented iterator.
407       */
408       friend inline const MatrixIterator operator+( const MatrixIterator& it, size_t inc ) noexcept {
409          if( SO )
410             return MatrixIterator( *it.matrix_, it.row_ + inc, it.column_ );
411          else
412             return MatrixIterator( *it.matrix_, it.row_, it.column_ + inc );
413       }
414       //*******************************************************************************************
415 
416       //**Addition operator************************************************************************
417       /*!\brief Addition between an integral value and a MatrixIterator.
418       //
419       // \param inc The number of elements the iterator is incremented.
420       // \param it The iterator to be incremented.
421       // \return The incremented iterator.
422       */
423       friend inline const MatrixIterator operator+( size_t inc, const MatrixIterator& it ) noexcept {
424          if( SO )
425             return MatrixIterator( *it.matrix_, it.row_ + inc, it.column_ );
426          else
427             return MatrixIterator( *it.matrix_, it.row_, it.column_ + inc );
428       }
429       //*******************************************************************************************
430 
431       //**Subtraction operator*********************************************************************
432       /*!\brief Subtraction between a MatrixIterator and an integral value.
433       //
434       // \param it The iterator to be decremented.
435       // \param dec The number of elements the iterator is decremented.
436       // \return The decremented iterator.
437       */
438       friend inline const MatrixIterator operator-( const MatrixIterator& it, size_t dec ) noexcept {
439          if( SO )
440             return MatrixIterator( *it.matrix_, it.row_ - dec, it.column_ );
441          else
442             return MatrixIterator( *it.matrix_, it.row_, it.column_ - dec );
443       }
444       //*******************************************************************************************
445 
446     private:
447       //**Member variables*************************************************************************
448       MatrixType* matrix_;  //!< Reference to the adapted dense matrix.
449       size_t      row_;     //!< The current row index of the iterator.
450       size_t      column_;  //!< The current column index of the iterator.
451       //*******************************************************************************************
452 
453       //**Friend declarations**********************************************************************
454       template< typename MatrixType2 > friend class MatrixIterator;
455       //*******************************************************************************************
456    };
457    //**********************************************************************************************
458 
459    //**Type definitions****************************************************************************
460    using Iterator      = MatrixIterator<MT>;        //!< Iterator over non-constant elements.
461    using ConstIterator = MatrixIterator<const MT>;  //!< Iterator over constant elements.
462    //**********************************************************************************************
463 
464    //**Compilation flags***************************************************************************
465    //! Compilation switch for the expression template evaluation strategy.
466    static constexpr bool simdEnabled = false;
467 
468    //! Compilation switch for the expression template assignment strategy.
469    static constexpr bool smpAssignable = ( MT::smpAssignable && !IsSMPAssignable_v<ET> );
470    //**********************************************************************************************
471 
472    //**Constructors********************************************************************************
473    /*!\name Constructors */
474    //@{
475             inline SymmetricMatrix();
476    explicit inline SymmetricMatrix( size_t n );
477 
478    inline SymmetricMatrix( ElementType* ptr, size_t n );
479    inline SymmetricMatrix( ElementType* ptr, size_t n, size_t nn );
480 
481    inline SymmetricMatrix( const SymmetricMatrix& m );
482    inline SymmetricMatrix( SymmetricMatrix&& m ) noexcept;
483 
484    template< typename MT2 > inline SymmetricMatrix( const Matrix<MT2,SO>&  m );
485    template< typename MT2 > inline SymmetricMatrix( const Matrix<MT2,!SO>& m );
486    //@}
487    //**********************************************************************************************
488 
489    //**Destructor**********************************************************************************
490    /*!\name Destructor */
491    //@{
492    ~SymmetricMatrix() = default;
493    //@}
494    //**********************************************************************************************
495 
496    //**Data access functions***********************************************************************
497    /*!\name Data access functions */
498    //@{
499    inline Reference      operator()( size_t i, size_t j );
500    inline ConstReference operator()( size_t i, size_t j ) const;
501    inline Reference      at( size_t i, size_t j );
502    inline ConstReference at( size_t i, size_t j ) const;
503    inline ConstPointer   data  () const noexcept;
504    inline ConstPointer   data  ( size_t i ) const noexcept;
505    inline Iterator       begin ( size_t i );
506    inline ConstIterator  begin ( size_t i ) const;
507    inline ConstIterator  cbegin( size_t i ) const;
508    inline Iterator       end   ( size_t i );
509    inline ConstIterator  end   ( size_t i ) const;
510    inline ConstIterator  cend  ( size_t i ) const;
511    //@}
512    //**********************************************************************************************
513 
514    //**Assignment operators************************************************************************
515    /*!\name Assignment operators */
516    //@{
517    inline SymmetricMatrix& operator=( const SymmetricMatrix& rhs );
518    inline SymmetricMatrix& operator=( SymmetricMatrix&& rhs ) noexcept;
519 
520    template< typename MT2 >
521    inline auto operator=( const Matrix<MT2,SO>& rhs )
522       -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
523 
524    template< typename MT2 >
525    inline auto operator=( const Matrix<MT2,SO>& rhs )
526       -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
527 
528    template< typename MT2 >
529    inline auto operator=( const Matrix<MT2,!SO>& rhs ) -> SymmetricMatrix&;
530 
531    template< typename MT2 >
532    inline auto operator+=( const Matrix<MT2,SO>& rhs )
533       -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
534 
535    template< typename MT2 >
536    inline auto operator+=( const Matrix<MT2,SO>& rhs )
537       -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
538 
539    template< typename MT2 >
540    inline auto operator+=( const Matrix<MT2,!SO>& rhs ) -> SymmetricMatrix&;
541 
542    template< typename MT2 >
543    inline auto operator-=( const Matrix<MT2,SO>& rhs )
544       -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
545 
546    template< typename MT2 >
547    inline auto operator-=( const Matrix<MT2,SO>& rhs )
548       -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
549 
550    template< typename MT2 >
551    inline auto operator-=( const Matrix<MT2,!SO>& rhs ) -> SymmetricMatrix&;
552 
553    template< typename MT2 >
554    inline auto operator%=( const Matrix<MT2,SO>& rhs )
555       -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
556 
557    template< typename MT2 >
558    inline auto operator%=( const Matrix<MT2,SO>& rhs )
559       -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >;
560 
561    template< typename MT2 >
562    inline auto operator%=( const Matrix<MT2,!SO>& rhs ) -> SymmetricMatrix&;
563 
564    template< typename ST >
565    inline auto operator*=( ST rhs ) -> EnableIf_t< IsScalar_v<ST>, SymmetricMatrix& >;
566 
567    template< typename ST >
568    inline auto operator/=( ST rhs ) -> EnableIf_t< IsScalar_v<ST>, SymmetricMatrix& >;
569    //@}
570    //**********************************************************************************************
571 
572    //**Utility functions***************************************************************************
573    /*!\name Utility functions */
574    //@{
575    inline size_t rows() const noexcept;
576    inline size_t columns() const noexcept;
577    inline size_t spacing() const noexcept;
578    inline size_t capacity() const noexcept;
579    inline size_t capacity( size_t i ) const noexcept;
580    inline size_t nonZeros() const;
581    inline size_t nonZeros( size_t i ) const;
582    inline void   reset();
583    inline void   reset( size_t i );
584    inline void   clear();
585           void   resize ( size_t n, bool preserve=true );
586    inline void   extend ( size_t n, bool preserve=true );
587    inline void   reserve( size_t elements );
588    inline void   shrinkToFit();
589    inline void   swap( SymmetricMatrix& m ) noexcept;
590    //@}
591    //**********************************************************************************************
592 
593    //**Numeric functions***************************************************************************
594    /*!\name Numeric functions */
595    //@{
596    inline SymmetricMatrix& transpose();
597    inline SymmetricMatrix& ctranspose();
598 
599    template< typename Other > inline SymmetricMatrix& scale( const Other& scalar );
600    //@}
601    //**********************************************************************************************
602 
603    //**Debugging functions*************************************************************************
604    /*!\name Utility functions */
605    //@{
606    inline bool isIntact() const noexcept;
607    //@}
608    //**********************************************************************************************
609 
610    //**Expression template evaluation functions****************************************************
611    /*!\name Expression template evaluation functions */
612    //@{
613    template< typename Other > inline bool canAlias ( const Other* alias ) const noexcept;
614    template< typename Other > inline bool isAliased( const Other* alias ) const noexcept;
615 
616    inline bool isAligned   () const noexcept;
617    inline bool canSMPAssign() const noexcept;
618    //@}
619    //**********************************************************************************************
620 
621  private:
622    //**Expression template evaluation functions****************************************************
623    /*!\name Expression template evaluation functions */
624    //@{
625    template< typename MT2 > inline void assign     (       DenseMatrix <MT2,SO>& rhs );
626    template< typename MT2 > inline void assign     ( const DenseMatrix <MT2,SO>& rhs );
627    template< typename MT2 > inline void assign     ( const SparseMatrix<MT2,SO>& rhs );
628    template< typename MT2 > inline void addAssign  ( const DenseMatrix <MT2,SO>& rhs );
629    template< typename MT2 > inline void addAssign  ( const SparseMatrix<MT2,SO>& rhs );
630    template< typename MT2 > inline void subAssign  ( const DenseMatrix <MT2,SO>& rhs );
631    template< typename MT2 > inline void subAssign  ( const SparseMatrix<MT2,SO>& rhs );
632    template< typename MT2 > inline void schurAssign( const DenseMatrix <MT2,SO>& rhs );
633    template< typename MT2 > inline void schurAssign( const SparseMatrix<MT2,SO>& rhs );
634    //@}
635    //**********************************************************************************************
636 
637    //**Member variables****************************************************************************
638    /*!\name Member variables */
639    //@{
640    MT matrix_;  //!< The adapted dense matrix.
641    //@}
642    //**********************************************************************************************
643 
644    //**Friend declarations*************************************************************************
645    template< RelaxationFlag RF, typename MT2, bool SO2, bool DF2, bool SF2 >
646    friend bool isDefault( const SymmetricMatrix<MT2,SO2,DF2,SF2>& m );
647    //**********************************************************************************************
648 
649    //**Compile time checks*************************************************************************
650    BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE        ( MT );
651    BLAZE_CONSTRAINT_MUST_NOT_BE_REFERENCE_TYPE       ( MT );
652    BLAZE_CONSTRAINT_MUST_NOT_BE_POINTER_TYPE         ( MT );
653    BLAZE_CONSTRAINT_MUST_NOT_BE_CONST                ( MT );
654    BLAZE_CONSTRAINT_MUST_NOT_BE_VOLATILE             ( MT );
655    BLAZE_CONSTRAINT_MUST_NOT_BE_VIEW_TYPE            ( MT );
656    BLAZE_CONSTRAINT_MUST_NOT_BE_COMPUTATION_TYPE     ( MT );
657    BLAZE_CONSTRAINT_MUST_NOT_BE_TRANSFORMATION_TYPE  ( MT );
658    BLAZE_CONSTRAINT_MUST_NOT_BE_SYMMETRIC_MATRIX_TYPE( MT );
659    BLAZE_CONSTRAINT_MUST_NOT_BE_HERMITIAN_MATRIX_TYPE( MT );
660    BLAZE_CONSTRAINT_MUST_NOT_BE_LOWER_MATRIX_TYPE    ( MT );
661    BLAZE_CONSTRAINT_MUST_NOT_BE_UPPER_MATRIX_TYPE    ( MT );
662    BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( OT, !SO );
663    BLAZE_CONSTRAINT_MUST_BE_MATRIX_WITH_STORAGE_ORDER( TT, !SO );
664    BLAZE_CONSTRAINT_MUST_NOT_BE_SCALAR_TYPE          ( ElementType );
665    BLAZE_STATIC_ASSERT( ( Size_v<MT,0UL> == Size_v<MT,1UL> ) );
666    //**********************************************************************************************
667 };
668 /*! \endcond */
669 //*************************************************************************************************
670 
671 
672 
673 
674 //=================================================================================================
675 //
676 //  CONSTRUCTORS
677 //
678 //=================================================================================================
679 
680 //*************************************************************************************************
681 /*! \cond BLAZE_INTERNAL */
682 /*!\brief The default constructor for SymmetricMatrix.
683 */
684 template< typename MT  // Type of the adapted dense matrix
685         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix()686 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix()
687    : matrix_()  // The adapted dense matrix
688 {
689    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
690 }
691 /*! \endcond */
692 //*************************************************************************************************
693 
694 
695 //*************************************************************************************************
696 /*! \cond BLAZE_INTERNAL */
697 /*!\brief Constructor for a matrix of size \f$ n \times n \f$.
698 //
699 // \param n The number of rows and columns of the matrix.
700 */
701 template< typename MT  // Type of the adapted dense matrix
702         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix(size_t n)703 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( size_t n )
704    : matrix_( n, n )  // The adapted dense matrix
705 {
706    BLAZE_CONSTRAINT_MUST_BE_RESIZABLE_TYPE( MT );
707 
708    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
709 }
710 /*! \endcond */
711 //*************************************************************************************************
712 
713 
714 //*************************************************************************************************
715 /*! \cond BLAZE_INTERNAL */
716 /*!\brief Constructor for a symmetric custom matrix of size \f$ n \times n \f$.
717 //
718 // \param ptr The array of elements to be used by the matrix.
719 // \param n The number of rows and columns of the array of elements.
720 // \exception std::invalid_argument Invalid setup of symmetric custom matrix.
721 //
722 // This constructor creates an unpadded symmetric custom matrix of size \f$ n \times n \f$:
723 
724    \code
725    using blaze::SymmetricMatrix;
726    using blaze::CustomMatrix;
727    using blaze::unaligned;
728    using blaze::unpadded;
729 
730    using Type = StaticMatrix<int,3UL,3UL>;
731 
732    std::vector<Type> memory( 9UL );
733    SymmetricMatrix< CustomMatrix<Type,unaligned,unpadded> > A( memory.data(), 3UL );
734    \endcode
735 
736 // The construction fails if ...
737 //
738 //  - ... the passed pointer is \c nullptr;
739 //  - ... the alignment flag \a AF is set to \a aligned, but the passed pointer is not properly
740 //    aligned according to the available instruction set (SSE, AVX, ...);
741 //  - ... the values in the given array do not represent a symmetric matrix.
742 //
743 // In all failure cases a \a std::invalid_argument exception is thrown.
744 //
745 // \note This constructor is \b NOT available for padded symmetric custom matrices!
746 // \note The matrix does \b NOT take responsibility for the given array of elements!
747 */
748 template< typename MT  // Type of the adapted dense matrix
749         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix(ElementType * ptr,size_t n)750 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( ElementType* ptr, size_t n )
751    : matrix_( ptr, n, n )  // The adapted dense matrix
752 {
753    if( !isSymmetric( matrix_ ) ) {
754       BLAZE_THROW_INVALID_ARGUMENT( "Invalid setup of symmetric matrix" );
755    }
756 
757    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
758 }
759 /*! \endcond */
760 //*************************************************************************************************
761 
762 
763 //*************************************************************************************************
764 /*! \cond BLAZE_INTERNAL */
765 /*!\brief Constructor for a symmetric custom matrix of size \f$ n \times n \f$.
766 //
767 // \param ptr The array of elements to be used by the matrix.
768 // \param n The number of rows and columns of the array of elements.
769 // \param nn The total number of elements between two rows/columns.
770 // \exception std::invalid_argument Invalid setup of symmetric custom matrix.
771 //
772 // This constructor creates a symmetric custom matrix of size \f$ n \times n \f$:
773 
774    \code
775    using blaze::SymmetricMatrix;
776    using blaze::CustomMatrix;
777    using blaze::unaligned;
778    using blaze::padded;
779 
780    using Type = StaticMatrix<int,3UL,3UL>;
781 
782    std::vector<Type> memory( 24UL );
783    SymmetricMatrix< CustomMatrix<Type,unaligned,padded> > A( memory.data(), 3UL, 8UL );
784    \endcode
785 
786 // The construction fails if ...
787 //
788 //  - ... the passed pointer is \c nullptr;
789 //  - ... the alignment flag \a AF is set to \a aligned, but the passed pointer is not properly
790 //    aligned according to the available instruction set (SSE, AVX, ...);
791 //  - ... the specified spacing \a nn is insufficient for the given data type \a Type and the
792 //    available instruction set;
793 //  - ... the values in the given array do not represent a symmetric matrix.
794 //
795 // In all failure cases a \a std::invalid_argument exception is thrown.
796 //
797 // \note The matrix does \b NOT take responsibility for the given array of elements!
798 */
799 template< typename MT  // Type of the adapted dense matrix
800         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix(ElementType * ptr,size_t n,size_t nn)801 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( ElementType* ptr, size_t n, size_t nn )
802    : matrix_( ptr, n, n, nn )  // The adapted dense matrix
803 {
804    if( !isSymmetric( matrix_ ) ) {
805       BLAZE_THROW_INVALID_ARGUMENT( "Invalid setup of symmetric matrix" );
806    }
807 
808    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
809 }
810 /*! \endcond */
811 //*************************************************************************************************
812 
813 
814 //*************************************************************************************************
815 /*! \cond BLAZE_INTERNAL */
816 /*!\brief The copy constructor for SymmetricMatrix.
817 //
818 // \param m The symmetric matrix to be copied.
819 */
820 template< typename MT  // Type of the adapted dense matrix
821         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix(const SymmetricMatrix & m)822 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( const SymmetricMatrix& m )
823    : matrix_( m.matrix_ )  // The adapted dense matrix
824 {
825    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
826    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
827 }
828 /*! \endcond */
829 //*************************************************************************************************
830 
831 
832 //*************************************************************************************************
833 /*! \cond BLAZE_INTERNAL */
834 /*!\brief The move constructor for SymmetricMatrix.
835 //
836 // \param m The symmetric matrix to be moved into this instance.
837 */
838 template< typename MT  // Type of the adapted dense matrix
839         , bool SO >    // Storage order of the adapted dense matrix
SymmetricMatrix(SymmetricMatrix && m)840 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( SymmetricMatrix&& m ) noexcept
841    : matrix_( std::move( m.matrix_ ) )  // The adapted dense matrix
842 {
843    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
844    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
845 }
846 /*! \endcond */
847 //*************************************************************************************************
848 
849 
850 //*************************************************************************************************
851 /*! \cond BLAZE_INTERNAL */
852 /*!\brief Conversion constructor from different matrices with the same storage order.
853 //
854 // \param m Matrix to be copied.
855 // \exception std::invalid_argument Invalid setup of symmetric matrix.
856 //
857 // This constructor initializes the symmetric matrix as a copy of the given matrix. In case the
858 // given matrix is not a symmetric matrix, a \a std::invalid_argument exception is thrown.
859 */
860 template< typename MT     // Type of the adapted dense matrix
861         , bool SO >       // Storage order of the adapted dense matrix
862 template< typename MT2 >  // Type of the foreign matrix
SymmetricMatrix(const Matrix<MT2,SO> & m)863 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( const Matrix<MT2,SO>& m )
864    : matrix_()  // The adapted dense matrix
865 {
866    using blaze::resize;
867 
868    using RT  = RemoveAdaptor_t<ResultType_t<MT2> >;
869    using Tmp = If_t< IsComputation_v<MT2>, RT, const MT2& >;
870 
871    if( IsSymmetric_v<MT2> ) {
872       resize( matrix_, (*m).rows(), (*m).columns() );
873       assign( *m );
874    }
875    else {
876       Tmp tmp( *m );
877 
878       if( !isSymmetric( tmp ) ) {
879          BLAZE_THROW_INVALID_ARGUMENT( "Invalid setup of symmetric matrix" );
880       }
881 
882       resize( matrix_, tmp.rows(), tmp.rows() );
883       assign( tmp );
884    }
885 
886    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
887    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
888 }
889 /*! \endcond */
890 //*************************************************************************************************
891 
892 
893 //*************************************************************************************************
894 /*! \cond BLAZE_INTERNAL */
895 /*!\brief Conversion constructor from different matrices with opposite storage order.
896 //
897 // \param m Matrix to be copied.
898 // \exception std::invalid_argument Invalid setup of symmetric matrix.
899 //
900 // This constructor initializes the symmetric matrix as a copy of the given matrix. In case the
901 // given matrix is not a symmetric matrix, a \a std::invalid_argument exception is thrown.
902 */
903 template< typename MT     // Type of the adapted dense matrix
904         , bool SO >       // Storage order of the adapted dense matrix
905 template< typename MT2 >  // Type of the foreign matrix
SymmetricMatrix(const Matrix<MT2,!SO> & m)906 inline SymmetricMatrix<MT,SO,true,false>::SymmetricMatrix( const Matrix<MT2,!SO>& m )
907    : matrix_()  // The adapted dense matrix
908 {
909    using blaze::resize;
910 
911    using RT  = RemoveAdaptor_t< ResultType_t<MT2> >;
912    using Tmp = If_t< IsComputation_v<MT2>, RT, const MT2& >;
913 
914    if( IsSymmetric_v<MT2> ) {
915       resize( matrix_, (*m).rows(), (*m).columns() );
916       assign( trans( *m ) );
917    }
918    else {
919       Tmp tmp( *m );
920 
921       if( !isSymmetric( tmp ) ) {
922          BLAZE_THROW_INVALID_ARGUMENT( "Invalid setup of symmetric matrix" );
923       }
924 
925       resize( matrix_, tmp.rows(), tmp.rows() );
926       assign( trans( tmp ) );
927    }
928 
929    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
930    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
931 }
932 /*! \endcond */
933 //*************************************************************************************************
934 
935 
936 
937 
938 //=================================================================================================
939 //
940 //  DATA ACCESS FUNCTIONS
941 //
942 //=================================================================================================
943 
944 //*************************************************************************************************
945 /*! \cond BLAZE_INTERNAL */
946 /*!\brief 2D-access to the matrix elements.
947 //
948 // \param i Access index for the row. The index has to be in the range \f$[0..N-1]\f$.
949 // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
950 // \return Reference to the accessed value.
951 //
952 // The function call operator provides access to both the elements at position (i,j) and (j,i).
953 // In order to preserve the symmetry of the matrix, any modification to one of the elements will
954 // also be applied to the other element.
955 //
956 // Note that this function only performs an index check in case BLAZE_USER_ASSERT() is active. In
957 // contrast, the at() function is guaranteed to perform a check of the given access indices.
958 */
959 template< typename MT  // Type of the adapted dense matrix
960         , bool SO >    // Storage order of the adapted dense matrix
961 inline typename SymmetricMatrix<MT,SO,true,false>::Reference
operator()962    SymmetricMatrix<MT,SO,true,false>::operator()( size_t i, size_t j )
963 {
964    BLAZE_USER_ASSERT( i<rows()   , "Invalid row access index"    );
965    BLAZE_USER_ASSERT( j<columns(), "Invalid column access index" );
966 
967    if( ( !SO && i > j ) || ( SO && i < j ) )
968       return matrix_(i,j);
969    else
970       return matrix_(j,i);
971 }
972 /*! \endcond */
973 //*************************************************************************************************
974 
975 
976 //*************************************************************************************************
977 /*! \cond BLAZE_INTERNAL */
978 /*!\brief 2D-access to the matrix elements.
979 //
980 // \param i Access index for the row. The index has to be in the range \f$[0..N-1]\f$.
981 // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
982 // \return Reference to the accessed value.
983 //
984 // The function call operator provides access to both the elements at position (i,j) and (j,i).
985 // In order to preserve the symmetry of the matrix, any modification to one of the elements will
986 // also be applied to the other element.
987 //
988 // Note that this function only performs an index check in case BLAZE_USER_ASSERT() is active. In
989 // contrast, the at() function is guaranteed to perform a check of the given access indices.
990 */
991 template< typename MT  // Type of the adapted dense matrix
992         , bool SO >    // Storage order of the adapted dense matrix
993 inline typename SymmetricMatrix<MT,SO,true,false>::ConstReference
operator()994    SymmetricMatrix<MT,SO,true,false>::operator()( size_t i, size_t j ) const
995 {
996    BLAZE_USER_ASSERT( i<rows()   , "Invalid row access index"    );
997    BLAZE_USER_ASSERT( j<columns(), "Invalid column access index" );
998 
999    if( ( !SO && i > j ) || ( SO && i < j ) )
1000       return matrix_(i,j);
1001    else
1002       return matrix_(j,i);
1003 }
1004 /*! \endcond */
1005 //*************************************************************************************************
1006 
1007 
1008 //*************************************************************************************************
1009 /*! \cond BLAZE_INTERNAL */
1010 /*!\brief Checked access to the matrix elements.
1011 //
1012 // \param i Access index for the row. The index has to be in the range \f$[0..N-1]\f$.
1013 // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
1014 // \return Reference to the accessed value.
1015 // \exception std::out_of_range Invalid matrix access index.
1016 //
1017 // The function call operator provides access to both the elements at position (i,j) and (j,i).
1018 // In order to preserve the symmetry of the matrix, any modification to one of the elements will
1019 // also be applied to the other element.
1020 //
1021 // Note that in contrast to the subscript operator this function always performs a check of the
1022 // given access indices.
1023 */
1024 template< typename MT  // Type of the adapted dense matrix
1025         , bool SO >    // Storage order of the adapted dense matrix
1026 inline typename SymmetricMatrix<MT,SO,true,false>::Reference
at(size_t i,size_t j)1027    SymmetricMatrix<MT,SO,true,false>::at( size_t i, size_t j )
1028 {
1029    if( i >= rows() ) {
1030       BLAZE_THROW_OUT_OF_RANGE( "Invalid row access index" );
1031    }
1032    if( j >= columns() ) {
1033       BLAZE_THROW_OUT_OF_RANGE( "Invalid column access index" );
1034    }
1035    return (*this)(i,j);
1036 }
1037 /*! \endcond */
1038 //*************************************************************************************************
1039 
1040 
1041 //*************************************************************************************************
1042 /*! \cond BLAZE_INTERNAL */
1043 /*!\brief Checked access to the matrix elements.
1044 //
1045 // \param i Access index for the row. The index has to be in the range \f$[0..N-1]\f$.
1046 // \param j Access index for the column. The index has to be in the range \f$[0..N-1]\f$.
1047 // \return Reference to the accessed value.
1048 // \exception std::out_of_range Invalid matrix access index.
1049 //
1050 // The function call operator provides access to both the elements at position (i,j) and (j,i).
1051 // In order to preserve the symmetry of the matrix, any modification to one of the elements will
1052 // also be applied to the other element.
1053 //
1054 // Note that in contrast to the subscript operator this function always performs a check of the
1055 // given access indices.
1056 */
1057 template< typename MT  // Type of the adapted dense matrix
1058         , bool SO >    // Storage order of the adapted dense matrix
1059 inline typename SymmetricMatrix<MT,SO,true,false>::ConstReference
at(size_t i,size_t j)1060    SymmetricMatrix<MT,SO,true,false>::at( size_t i, size_t j ) const
1061 {
1062    if( i >= rows() ) {
1063       BLAZE_THROW_OUT_OF_RANGE( "Invalid row access index" );
1064    }
1065    if( j >= columns() ) {
1066       BLAZE_THROW_OUT_OF_RANGE( "Invalid column access index" );
1067    }
1068    return (*this)(i,j);
1069 }
1070 /*! \endcond */
1071 //*************************************************************************************************
1072 
1073 
1074 //*************************************************************************************************
1075 /*! \cond BLAZE_INTERNAL */
1076 /*!\brief Low-level data access to the matrix elements.
1077 //
1078 // \return Pointer to the internal element storage.
1079 //
1080 // This function returns a pointer to the internal storage of the symmetric matrix. Note that you
1081 // can NOT assume that all matrix elements lie adjacent to each other! The symmetric matrix may
1082 // use techniques such as padding to improve the alignment of the data. Whereas the number of
1083 // elements within a row/column are given by the \c rows() and \c columns() member functions,
1084 // respectively, the total number of elements including padding is given by the \c spacing()
1085 // member function. Also note that you can NOT assume that the symmetric matrix stores all its
1086 // elements. It may choose to store its elements in a lower or upper triangular matrix fashion.
1087 */
1088 template< typename MT  // Type of the adapted dense matrix
1089         , bool SO >    // Storage order of the adapted dense matrix
1090 inline typename SymmetricMatrix<MT,SO,true,false>::ConstPointer
data()1091    SymmetricMatrix<MT,SO,true,false>::data() const noexcept
1092 {
1093    return matrix_.data();
1094 }
1095 /*! \endcond */
1096 //*************************************************************************************************
1097 
1098 
1099 //*************************************************************************************************
1100 /*! \cond BLAZE_INTERNAL */
1101 /*!\brief Low-level data access to the matrix elements of row/column \a i.
1102 //
1103 // \param i The row/column index.
1104 // \return Pointer to the internal element storage.
1105 //
1106 // This function returns a pointer to the internal storage for the elements in row/column \a i.
1107 // Note that you can NOT assume that the symmetric matrix stores all its elements. It may choose
1108 // to store its elements in a lower or upper triangular matrix fashion.
1109 */
1110 template< typename MT  // Type of the adapted dense matrix
1111         , bool SO >    // Storage order of the adapted dense matrix
1112 inline typename SymmetricMatrix<MT,SO,true,false>::ConstPointer
data(size_t i)1113    SymmetricMatrix<MT,SO,true,false>::data( size_t i ) const noexcept
1114 {
1115    return matrix_.data(i);
1116 }
1117 /*! \endcond */
1118 //*************************************************************************************************
1119 
1120 
1121 //*************************************************************************************************
1122 /*! \cond BLAZE_INTERNAL */
1123 /*!\brief Returns an iterator to the first element of row/column \a i.
1124 //
1125 // \param i The row/column index.
1126 // \return Iterator to the first element of row/column \a i.
1127 //
1128 // This function returns a row/column iterator to the first element of row/column \a i. In case
1129 // the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator to
1130 // the first element of row \a i, in case it adapts a \a columnMajor dense matrix the function
1131 // returns an iterator to the first element of column \a i.
1132 */
1133 template< typename MT  // Type of the adapted dense matrix
1134         , bool SO >    // Storage order of the adapted dense matrix
1135 inline typename SymmetricMatrix<MT,SO,true,false>::Iterator
begin(size_t i)1136    SymmetricMatrix<MT,SO,true,false>::begin( size_t i )
1137 {
1138    if( SO )
1139       return Iterator( matrix_, 0UL, i );
1140    else
1141       return Iterator( matrix_, i, 0UL );
1142 }
1143 /*! \endcond */
1144 //*************************************************************************************************
1145 
1146 
1147 //*************************************************************************************************
1148 /*! \cond BLAZE_INTERNAL */
1149 /*!\brief Returns an iterator to the first element of row/column \a i.
1150 //
1151 // \param i The row/column index.
1152 // \return Iterator to the first element of row/column \a i.
1153 //
1154 // This function returns a row/column iterator to the first element of row/column \a i. In case
1155 // the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator to
1156 // the first element of row \a i, in case it adapts a \a columnMajor dense matrix the function
1157 // returns an iterator to the first element of column \a i.
1158 */
1159 template< typename MT  // Type of the adapted dense matrix
1160         , bool SO >    // Storage order of the adapted dense matrix
1161 inline typename SymmetricMatrix<MT,SO,true,false>::ConstIterator
begin(size_t i)1162    SymmetricMatrix<MT,SO,true,false>::begin( size_t i ) const
1163 {
1164    if( SO )
1165       return ConstIterator( matrix_, 0UL, i );
1166    else
1167       return ConstIterator( matrix_, i, 0UL );
1168 }
1169 /*! \endcond */
1170 //*************************************************************************************************
1171 
1172 
1173 //*************************************************************************************************
1174 /*! \cond BLAZE_INTERNAL */
1175 /*!\brief Returns an iterator to the first element of row/column \a i.
1176 //
1177 // \param i The row/column index.
1178 // \return Iterator to the first element of row/column \a i.
1179 //
1180 // This function returns a row/column iterator to the first element of row/column \a i. In case
1181 // the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator to
1182 // the first element of row \a i, in case it adapts a \a columnMajor dense matrix the function
1183 // returns an iterator to the first element of column \a i.
1184 */
1185 template< typename MT  // Type of the adapted dense matrix
1186         , bool SO >    // Storage order of the adapted dense matrix
1187 inline typename SymmetricMatrix<MT,SO,true,false>::ConstIterator
cbegin(size_t i)1188    SymmetricMatrix<MT,SO,true,false>::cbegin( size_t i ) const
1189 {
1190    if( SO )
1191       return ConstIterator( matrix_, 0UL, i );
1192    else
1193       return ConstIterator( matrix_, i, 0UL );
1194 }
1195 /*! \endcond */
1196 //*************************************************************************************************
1197 
1198 
1199 //*************************************************************************************************
1200 /*! \cond BLAZE_INTERNAL */
1201 /*!\brief Returns an iterator just past the last element of row/column \a i.
1202 //
1203 // \param i The row/column index.
1204 // \return Iterator just past the last element of row/column \a i.
1205 //
1206 // This function returns an row/column iterator just past the last element of row/column \a i.
1207 // In case the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator
1208 // just past the last element of row \a i, in case it adapts a \a columnMajor dense matrix the
1209 // function returns an iterator just past the last element of column \a i.
1210 */
1211 template< typename MT  // Type of the adapted dense matrix
1212         , bool SO >    // Storage order of the adapted dense matrix
1213 inline typename SymmetricMatrix<MT,SO,true,false>::Iterator
end(size_t i)1214    SymmetricMatrix<MT,SO,true,false>::end( size_t i )
1215 {
1216    if( SO )
1217       return Iterator( matrix_, rows(), i );
1218    else
1219       return Iterator( matrix_, i, columns() );
1220 }
1221 /*! \endcond */
1222 //*************************************************************************************************
1223 
1224 
1225 //*************************************************************************************************
1226 /*! \cond BLAZE_INTERNAL */
1227 /*!\brief Returns an iterator just past the last element of row/column \a i.
1228 //
1229 // \param i The row/column index.
1230 // \return Iterator just past the last element of row/column \a i.
1231 //
1232 // This function returns an row/column iterator just past the last element of row/column \a i.
1233 // In case the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator
1234 // just past the last element of row \a i, in case it adapts a \a columnMajor dense matrix the
1235 // function returns an iterator just past the last element of column \a i.
1236 */
1237 template< typename MT  // Type of the adapted dense matrix
1238         , bool SO >    // Storage order of the adapted dense matrix
1239 inline typename SymmetricMatrix<MT,SO,true,false>::ConstIterator
end(size_t i)1240    SymmetricMatrix<MT,SO,true,false>::end( size_t i ) const
1241 {
1242    if( SO )
1243       return ConstIterator( matrix_, rows(), i );
1244    else
1245       return ConstIterator( matrix_, i, columns() );
1246 }
1247 /*! \endcond */
1248 //*************************************************************************************************
1249 
1250 
1251 //*************************************************************************************************
1252 /*! \cond BLAZE_INTERNAL */
1253 /*!\brief Returns an iterator just past the last element of row/column \a i.
1254 //
1255 // \param i The row/column index.
1256 // \return Iterator just past the last element of row/column \a i.
1257 //
1258 // This function returns an row/column iterator just past the last element of row/column \a i.
1259 // In case the symmetric matrix adapts a \a rowMajor dense matrix the function returns an iterator
1260 // just past the last element of row \a i, in case it adapts a \a columnMajor dense matrix the
1261 // function returns an iterator just past the last element of column \a i.
1262 */
1263 template< typename MT  // Type of the adapted dense matrix
1264         , bool SO >    // Storage order of the adapted dense matrix
1265 inline typename SymmetricMatrix<MT,SO,true,false>::ConstIterator
cend(size_t i)1266    SymmetricMatrix<MT,SO,true,false>::cend( size_t i ) const
1267 {
1268    if( SO )
1269       return ConstIterator( matrix_, rows(), i );
1270    else
1271       return ConstIterator( matrix_, i, columns() );
1272 }
1273 /*! \endcond */
1274 //*************************************************************************************************
1275 
1276 
1277 
1278 
1279 //=================================================================================================
1280 //
1281 //  ASSIGNMENT OPERATORS
1282 //
1283 //=================================================================================================
1284 
1285 //*************************************************************************************************
1286 /*! \cond BLAZE_INTERNAL */
1287 /*!\brief Copy assignment operator for SymmetricMatrix.
1288 //
1289 // \param rhs Matrix to be copied.
1290 // \return Reference to the assigned matrix.
1291 //
1292 // If possible and necessary, the matrix is resized according to the given \f$ N \times N \f$
1293 // matrix and initialized as a copy of this matrix.
1294 */
1295 template< typename MT  // Type of the adapted dense matrix
1296         , bool SO >    // Storage order of the adapted dense matrix
1297 inline SymmetricMatrix<MT,SO,true,false>&
1298    SymmetricMatrix<MT,SO,true,false>::operator=( const SymmetricMatrix& rhs )
1299 {
1300    using blaze::resize;
1301 
1302    if( &rhs == this ) return *this;
1303 
1304    resize( matrix_, rhs.rows(), rhs.columns() );
1305    assign( rhs );
1306 
1307    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1308    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1309 
1310    return *this;
1311 }
1312 /*! \endcond */
1313 //*************************************************************************************************
1314 
1315 
1316 //*************************************************************************************************
1317 /*! \cond BLAZE_INTERNAL */
1318 /*!\brief Move assignment operator for SymmetricMatrix.
1319 //
1320 // \param rhs The matrix to be moved into this instance.
1321 // \return Reference to the assigned matrix.
1322 */
1323 template< typename MT  // Type of the adapted dense matrix
1324         , bool SO >    // Storage order of the adapted dense matrix
1325 inline SymmetricMatrix<MT,SO,true,false>&
1326    SymmetricMatrix<MT,SO,true,false>::operator=( SymmetricMatrix&& rhs ) noexcept
1327 {
1328    matrix_ = std::move( rhs.matrix_ );
1329 
1330    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1331    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1332 
1333    return *this;
1334 }
1335 /*! \endcond */
1336 //*************************************************************************************************
1337 
1338 
1339 //*************************************************************************************************
1340 /*! \cond BLAZE_INTERNAL */
1341 /*!\brief Assignment operator for general matrices.
1342 //
1343 // \param rhs The general matrix to be copied.
1344 // \return Reference to the assigned matrix.
1345 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1346 // \exception std::invalid_argument Matrix sizes do not match.
1347 //
1348 // If possible and necessary, the matrix is resized according to the given \f$ N \times N \f$
1349 // matrix and initialized as a copy of this matrix. If the matrix cannot be resized accordingly,
1350 // a \a std::invalid_argument exception is thrown. Also note that the given matrix must be a
1351 // symmetric matrix. Otherwise, a \a std::invalid_argument exception is thrown.
1352 */
1353 template< typename MT     // Type of the adapted dense matrix
1354         , bool SO >       // Storage order of the adapted dense matrix
1355 template< typename MT2 >  // Type of the right-hand side matrix
1356 inline auto SymmetricMatrix<MT,SO,true,false>::operator=( const Matrix<MT2,SO>& rhs )
1357    -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1358 {
1359    using blaze::resize;
1360 
1361    if( !IsSymmetric_v<MT2> && !isSymmetric( *rhs ) ) {
1362       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1363    }
1364 
1365    if( (*rhs).isAliased( this ) ) {
1366       SymmetricMatrix tmp( *rhs );
1367       swap( tmp );
1368    }
1369    else {
1370       resize( matrix_, (*rhs).rows(), (*rhs).columns() );
1371       if( IsSparseMatrix_v<MT2> )
1372          reset();
1373       assign( *rhs );
1374    }
1375 
1376    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1377    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1378 
1379    return *this;
1380 }
1381 /*! \endcond */
1382 //*************************************************************************************************
1383 
1384 
1385 //*************************************************************************************************
1386 /*! \cond BLAZE_INTERNAL */
1387 /*!\brief Assignment operator for matrix computations.
1388 //
1389 // \param rhs The matrix computation to be copied.
1390 // \return Reference to the assigned matrix.
1391 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1392 // \exception std::invalid_argument Matrix sizes do not match.
1393 //
1394 // If possible and necessary, the matrix is resized according to the given \f$ N \times N \f$
1395 // matrix and initialized as a copy of this matrix. If the matrix cannot be resized accordingly,
1396 // a \a std::invalid_argument exception is thrown. Also note that the given matrix must be a
1397 // symmetric matrix. Otherwise, a \a std::invalid_argument exception is thrown.
1398 */
1399 template< typename MT     // Type of the adapted dense matrix
1400         , bool SO >       // Storage order of the adapted dense matrix
1401 template< typename MT2 >  // Type of the right-hand side matrix
1402 inline auto SymmetricMatrix<MT,SO,true,false>::operator=( const Matrix<MT2,SO>& rhs )
1403    -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1404 {
1405    using blaze::resize;
1406 
1407    using Tmp = If_t< IsSymmetric_v<MT2>, CompositeType_t<MT2>, ResultType_t<MT2> >;
1408 
1409    if( !IsSquare_v<MT2> && !isSquare( *rhs ) ) {
1410       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1411    }
1412 
1413    Tmp tmp( *rhs );
1414 
1415    if( !IsSymmetric_v<Tmp> && !isSymmetric( tmp ) ) {
1416       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1417    }
1418 
1419    BLAZE_INTERNAL_ASSERT( !tmp.canAlias( this ), "Aliasing detected" );
1420 
1421    resize( matrix_, tmp.rows(), tmp.columns() );
1422    if( IsSparseMatrix_v<Tmp> )
1423       reset();
1424    assign( tmp );
1425 
1426    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1427    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1428 
1429    return *this;
1430 }
1431 /*! \endcond */
1432 //*************************************************************************************************
1433 
1434 
1435 //*************************************************************************************************
1436 /*! \cond BLAZE_INTERNAL */
1437 /*!\brief Assignment operator for matrices with opposite storage order.
1438 //
1439 // \param rhs The right-hand side matrix to be copied.
1440 // \return Reference to the assigned matrix.
1441 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1442 // \exception std::invalid_argument Matrix sizes do not match.
1443 //
1444 // If possible and necessary, the matrix is resized according to the given \f$ N \times N \f$
1445 // matrix and initialized as a copy of this matrix. If the matrix cannot be resized accordingly,
1446 // a \a std::invalid_argument exception is thrown. Also note that the given matrix must be a
1447 // symmetric matrix. Otherwise, a \a std::invalid_argument exception is thrown.
1448 */
1449 template< typename MT     // Type of the adapted dense matrix
1450         , bool SO >       // Storage order of the adapted dense matrix
1451 template< typename MT2 >  // Type of the right-hand side matrix
1452 inline auto SymmetricMatrix<MT,SO,true,false>::operator=( const Matrix<MT2,!SO>& rhs )
1453    -> SymmetricMatrix&
1454 {
1455    return this->operator=( trans( *rhs ) );
1456 }
1457 /*! \endcond */
1458 //*************************************************************************************************
1459 
1460 
1461 //*************************************************************************************************
1462 /*! \cond BLAZE_INTERNAL */
1463 /*!\brief Addition assignment operator for the addition of a general matrix (\f$ A+=B \f$).
1464 //
1465 // \param rhs The right-hand side general matrix to be added.
1466 // \return Reference to the matrix.
1467 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1468 //
1469 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1470 // is thrown. Also note that the result of the addition operation must be a symmetric matrix, i.e.
1471 // the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix, a
1472 // \a std::invalid_argument exception is thrown.
1473 */
1474 template< typename MT     // Type of the adapted dense matrix
1475         , bool SO >       // Storage order of the adapted dense matrix
1476 template< typename MT2 >  // Type of the right-hand side matrix
1477 inline auto SymmetricMatrix<MT,SO,true,false>::operator+=( const Matrix<MT2,SO>& rhs )
1478    -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1479 {
1480    if( !IsSymmetric_v<MT2> && !isSymmetric( *rhs ) ) {
1481       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1482    }
1483 
1484    addAssign( *rhs );
1485 
1486    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1487    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1488 
1489    return *this;
1490 }
1491 /*! \endcond */
1492 //*************************************************************************************************
1493 
1494 
1495 //*************************************************************************************************
1496 /*! \cond BLAZE_INTERNAL */
1497 /*!\brief Addition assignment operator for the addition of a matrix computation (\f$ A+=B \f$).
1498 //
1499 // \param rhs The right-hand side matrix computation to be added.
1500 // \return Reference to the matrix.
1501 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1502 //
1503 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1504 // is thrown. Also note that the result of the addition operation must be a symmetric matrix, i.e.
1505 // the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix, a
1506 // \a std::invalid_argument exception is thrown.
1507 */
1508 template< typename MT     // Type of the adapted dense matrix
1509         , bool SO >       // Storage order of the adapted dense matrix
1510 template< typename MT2 >  // Type of the right-hand side matrix
1511 inline auto SymmetricMatrix<MT,SO,true,false>::operator+=( const Matrix<MT2,SO>& rhs )
1512    -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1513 {
1514    using Tmp = If_t< IsSymmetric_v<MT2>, CompositeType_t<MT2>, ResultType_t<MT2> >;
1515 
1516    if( !IsSquare_v<MT2> && !isSquare( *rhs ) ) {
1517       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1518    }
1519 
1520    Tmp tmp( *rhs );
1521 
1522    if( !IsSymmetric_v<Tmp> && !isSymmetric( tmp ) ) {
1523       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1524    }
1525 
1526    BLAZE_INTERNAL_ASSERT( !tmp.canAlias( this ), "Aliasing detected" );
1527 
1528    addAssign( tmp );
1529 
1530    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1531    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1532 
1533    return *this;
1534 }
1535 /*! \endcond */
1536 //*************************************************************************************************
1537 
1538 
1539 //*************************************************************************************************
1540 /*! \cond BLAZE_INTERNAL */
1541 /*!\brief Addition assignment operator for the addition of a matrix with opposite storage order
1542 //        (\f$ A+=B \f$).
1543 //
1544 // \param rhs The right-hand side matrix to be added.
1545 // \return Reference to the matrix.
1546 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1547 //
1548 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1549 // is thrown. Also note that the result of the addition operation must be a symmetric matrix, i.e.
1550 // the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix, a
1551 // \a std::invalid_argument exception is thrown.
1552 */
1553 template< typename MT     // Type of the adapted dense matrix
1554         , bool SO >       // Storage order of the adapted dense matrix
1555 template< typename MT2 >  // Type of the right-hand side matrix
1556 inline auto SymmetricMatrix<MT,SO,true,false>::operator+=( const Matrix<MT2,!SO>& rhs )
1557    -> SymmetricMatrix&
1558 {
1559    return this->operator+=( trans( *rhs ) );
1560 }
1561 /*! \endcond */
1562 //*************************************************************************************************
1563 
1564 
1565 //*************************************************************************************************
1566 /*! \cond BLAZE_INTERNAL */
1567 /*!\brief Subtraction assignment operator for the subtraction of a general matrix (\f$ A-=B \f$).
1568 //
1569 // \param rhs The right-hand side general matrix to be subtracted.
1570 // \return Reference to the matrix.
1571 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1572 //
1573 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1574 // is thrown. Also note that the result of the subtraction operation must be a symmetric matrix,
1575 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1576 // a \a std::invalid_argument exception is thrown.
1577 */
1578 template< typename MT     // Type of the adapted dense matrix
1579         , bool SO >       // Storage order of the adapted dense matrix
1580 template< typename MT2 >  // Type of the right-hand side matrix
1581 inline auto SymmetricMatrix<MT,SO,true,false>::operator-=( const Matrix<MT2,SO>& rhs )
1582    -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1583 {
1584    if( !IsSymmetric_v<MT2> && !isSymmetric( *rhs ) ) {
1585       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1586    }
1587 
1588    subAssign( *rhs );
1589 
1590    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1591    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1592 
1593    return *this;
1594 }
1595 /*! \endcond */
1596 //*************************************************************************************************
1597 
1598 
1599 //*************************************************************************************************
1600 /*! \cond BLAZE_INTERNAL */
1601 /*!\brief Subtraction assignment operator for the subtraction of a matrix computation (\f$ A-=B \f$).
1602 //
1603 // \param rhs The right-hand side matrix computation to be subtracted.
1604 // \return Reference to the matrix.
1605 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1606 //
1607 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1608 // is thrown. Also note that the result of the subtraction operation must be a symmetric matrix,
1609 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1610 // a \a std::invalid_argument exception is thrown.
1611 */
1612 template< typename MT     // Type of the adapted dense matrix
1613         , bool SO >       // Storage order of the adapted dense matrix
1614 template< typename MT2 >  // Type of the right-hand side matrix
1615 inline auto SymmetricMatrix<MT,SO,true,false>::operator-=( const Matrix<MT2,SO>& rhs )
1616    -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1617 {
1618    using Tmp = If_t< IsSymmetric_v<MT2>, CompositeType_t<MT2>, ResultType_t<MT2> >;
1619 
1620    if( !IsSquare_v<MT2> && !isSquare( *rhs ) ) {
1621       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1622    }
1623 
1624    Tmp tmp( *rhs );
1625 
1626    if( !IsSymmetric_v<Tmp> && !isSymmetric( tmp ) ) {
1627       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1628    }
1629 
1630    BLAZE_INTERNAL_ASSERT( !tmp.canAlias( this ), "Aliasing detected" );
1631 
1632    subAssign( tmp );
1633 
1634    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1635    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1636 
1637    return *this;
1638 }
1639 /*! \endcond */
1640 //*************************************************************************************************
1641 
1642 
1643 //*************************************************************************************************
1644 /*! \cond BLAZE_INTERNAL */
1645 /*!\brief Subtraction assignment operator for the subtraction of a matrix with opposite storage
1646 //        order (\f$ A-=B \f$).
1647 //
1648 // \param rhs The right-hand side matrix to be subtracted.
1649 // \return Reference to the matrix.
1650 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1651 //
1652 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1653 // is thrown. Also note that the result of the subtraction operation must be a symmetric matrix,
1654 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1655 // a \a std::invalid_argument exception is thrown.
1656 */
1657 template< typename MT     // Type of the adapted dense matrix
1658         , bool SO >       // Storage order of the adapted dense matrix
1659 template< typename MT2 >  // Type of the right-hand side matrix
1660 inline auto SymmetricMatrix<MT,SO,true,false>::operator-=( const Matrix<MT2,!SO>& rhs )
1661    -> SymmetricMatrix&
1662 {
1663    return this->operator-=( trans( *rhs ) );
1664 }
1665 /*! \endcond */
1666 //*************************************************************************************************
1667 
1668 
1669 //*************************************************************************************************
1670 /*! \cond BLAZE_INTERNAL */
1671 /*!\brief Schur product assignment operator for the multiplication of a general matrix
1672 //        (\f$ A\circ=B \f$).
1673 //
1674 // \param rhs The right-hand side general matrix for the Schur product.
1675 // \return Reference to the matrix.
1676 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1677 //
1678 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1679 // is thrown. Also note that the result of the Schur product operation must be a symmetric matrix,
1680 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1681 // a \a std::invalid_argument exception is thrown.
1682 */
1683 template< typename MT     // Type of the adapted dense matrix
1684         , bool SO >       // Storage order of the adapted dense matrix
1685 template< typename MT2 >  // Type of the right-hand side matrix
1686 inline auto SymmetricMatrix<MT,SO,true,false>::operator%=( const Matrix<MT2,SO>& rhs )
1687    -> DisableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1688 {
1689    if( !IsSymmetric_v<MT2> && !isSymmetric( *rhs ) ) {
1690       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1691    }
1692 
1693    schurAssign( *rhs );
1694 
1695    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1696    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1697 
1698    return *this;
1699 }
1700 /*! \endcond */
1701 //*************************************************************************************************
1702 
1703 
1704 //*************************************************************************************************
1705 /*! \cond BLAZE_INTERNAL */
1706 /*!\brief Schur product assignment operator for the multiplication of a matrix computation
1707 //        (\f$ A&=B \f$).
1708 //
1709 // \param rhs The right-hand side matrix computation for the Schur product.
1710 // \return Reference to the matrix.
1711 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1712 //
1713 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1714 // is thrown. Also note that the result of the Schur product operation must be a symmetric matrix,
1715 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1716 // a \a std::invalid_argument exception is thrown.
1717 */
1718 template< typename MT     // Type of the adapted dense matrix
1719         , bool SO >       // Storage order of the adapted dense matrix
1720 template< typename MT2 >  // Type of the right-hand side matrix
1721 inline auto SymmetricMatrix<MT,SO,true,false>::operator%=( const Matrix<MT2,SO>& rhs )
1722    -> EnableIf_t< IsComputation_v<MT2>, SymmetricMatrix& >
1723 {
1724    using Tmp = If_t< IsSymmetric_v<MT2>, CompositeType_t<MT2>, ResultType_t<MT2> >;
1725 
1726    if( !IsSquare_v<MT2> && !isSquare( *rhs ) ) {
1727       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1728    }
1729 
1730    Tmp tmp( *rhs );
1731 
1732    if( !IsSymmetric_v<Tmp> && !isSymmetric( tmp ) ) {
1733       BLAZE_THROW_INVALID_ARGUMENT( "Invalid assignment to symmetric matrix" );
1734    }
1735 
1736    BLAZE_INTERNAL_ASSERT( !tmp.canAlias( this ), "Aliasing detected" );
1737 
1738    schurAssign( tmp );
1739 
1740    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
1741    BLAZE_INTERNAL_ASSERT( isIntact(), "Broken invariant detected" );
1742 
1743    return *this;
1744 }
1745 /*! \endcond */
1746 //*************************************************************************************************
1747 
1748 
1749 //*************************************************************************************************
1750 /*! \cond BLAZE_INTERNAL */
1751 /*!\brief Schur product assignment operator for the multiplication of a matrix with opposite
1752 //        storage order (\f$ A\circ=B \f$).
1753 //
1754 // \param rhs The right-hand side matrix for the Schur product.
1755 // \return Reference to the matrix.
1756 // \exception std::invalid_argument Invalid assignment to symmetric matrix.
1757 //
1758 // In case the current sizes of the two matrices don't match, a \a std::invalid_argument exception
1759 // is thrown. Also note that the result of the Schur product operation must be a symmetric matrix,
1760 // i.e. the given matrix must be a symmetric matrix. In case the result is not a symmetric matrix,
1761 // a \a std::invalid_argument exception is thrown.
1762 */
1763 template< typename MT     // Type of the adapted dense matrix
1764         , bool SO >       // Storage order of the adapted dense matrix
1765 template< typename MT2 >  // Type of the right-hand side matrix
1766 inline auto SymmetricMatrix<MT,SO,true,false>::operator%=( const Matrix<MT2,!SO>& rhs )
1767    -> SymmetricMatrix&
1768 {
1769    return this->operator%=( trans( *rhs ) );
1770 }
1771 /*! \endcond */
1772 //*************************************************************************************************
1773 
1774 
1775 //*************************************************************************************************
1776 /*! \cond BLAZE_INTERNAL */
1777 /*!\brief Multiplication assignment operator for the multiplication between a matrix and
1778 //        a scalar value (\f$ A*=s \f$).
1779 //
1780 // \param rhs The right-hand side scalar value for the multiplication.
1781 // \return Reference to the matrix.
1782 */
1783 template< typename MT    // Type of the adapted dense matrix
1784         , bool SO >      // Storage order of the adapted dense matrix
1785 template< typename ST >  // Data type of the right-hand side scalar
1786 inline auto SymmetricMatrix<MT,SO,true,false>::operator*=( ST rhs )
1787    -> EnableIf_t< IsScalar_v<ST>, SymmetricMatrix& >
1788 {
1789    if( SO ) {
1790       for( size_t j=0UL; j<columns(); ++j )
1791          for( size_t i=0UL; i<=j; ++i )
1792             matrix_(i,j) *= rhs;
1793    }
1794    else {
1795       for( size_t i=0UL; i<rows(); ++i )
1796          for( size_t j=0UL; j<=i; ++j )
1797             matrix_(i,j) *= rhs;
1798    }
1799 
1800    return *this;
1801 }
1802 /*! \endcond */
1803 //*************************************************************************************************
1804 
1805 
1806 //*************************************************************************************************
1807 /*! \cond BLAZE_INTERNAL */
1808 /*!\brief Division assignment operator for the division of a matrix by a scalar value
1809 //        (\f$ A/=s \f$).
1810 //
1811 // \param rhs The right-hand side scalar value for the division.
1812 // \return Reference to the matrix.
1813 */
1814 template< typename MT    // Type of the adapted dense matrix
1815         , bool SO >      // Storage order of the adapted dense matrix
1816 template< typename ST >  // Data type of the right-hand side scalar
1817 inline auto SymmetricMatrix<MT,SO,true,false>::operator/=( ST rhs )
1818    -> EnableIf_t< IsScalar_v<ST>, SymmetricMatrix& >
1819 {
1820    BLAZE_USER_ASSERT( !isZero( rhs ), "Division by zero detected" );
1821 
1822    if( SO ) {
1823       for( size_t j=0UL; j<columns(); ++j )
1824          for( size_t i=0UL; i<=j; ++i )
1825             matrix_(i,j) /= rhs;
1826    }
1827    else {
1828       for( size_t i=0UL; i<rows(); ++i )
1829          for( size_t j=0UL; j<=i; ++j )
1830             matrix_(i,j) /= rhs;
1831    }
1832 
1833    return *this;
1834 }
1835 /*! \endcond */
1836 //*************************************************************************************************
1837 
1838 
1839 
1840 
1841 //=================================================================================================
1842 //
1843 //  UTILITY FUNCTIONS
1844 //
1845 //=================================================================================================
1846 
1847 //*************************************************************************************************
1848 /*! \cond BLAZE_INTERNAL */
1849 /*!\brief Returns the current number of rows of the matrix.
1850 //
1851 // \return The number of rows of the matrix.
1852 */
1853 template< typename MT  // Type of the adapted dense matrix
1854         , bool SO >    // Storage order of the adapted dense matrix
rows()1855 inline size_t SymmetricMatrix<MT,SO,true,false>::rows() const noexcept
1856 {
1857    return matrix_.rows();
1858 }
1859 /*! \endcond */
1860 //*************************************************************************************************
1861 
1862 
1863 //*************************************************************************************************
1864 /*! \cond BLAZE_INTERNAL */
1865 /*!\brief Returns the current number of columns of the matrix.
1866 //
1867 // \return The number of columns of the matrix.
1868 */
1869 template< typename MT  // Type of the adapted dense matrix
1870         , bool SO >    // Storage order of the adapted dense matrix
columns()1871 inline size_t SymmetricMatrix<MT,SO,true,false>::columns() const noexcept
1872 {
1873    return matrix_.columns();
1874 }
1875 /*! \endcond */
1876 //*************************************************************************************************
1877 
1878 
1879 //*************************************************************************************************
1880 /*! \cond BLAZE_INTERNAL */
1881 /*!\brief Returns the spacing between the beginning of two rows/columns.
1882 //
1883 // \return The spacing between the beginning of two rows/columns.
1884 //
1885 // This function returns the spacing between the beginning of two rows/columns, i.e.
1886 // the total number of elements of a row/column. In case the symmetric matrix adapts a
1887 // \a rowMajor dense matrix the function returns the spacing between two rows, in case
1888 // it adapts a \a columnMajor dense matrix the function returns the spacing between two
1889 // columns.
1890 */
1891 template< typename MT  // Type of the adapted dense matrix
1892         , bool SO >    // Storage order of the adapted dense matrix
spacing()1893 inline size_t SymmetricMatrix<MT,SO,true,false>::spacing() const noexcept
1894 {
1895    return matrix_.spacing();
1896 }
1897 /*! \endcond */
1898 //*************************************************************************************************
1899 
1900 
1901 //*************************************************************************************************
1902 /*! \cond BLAZE_INTERNAL */
1903 /*!\brief Returns the maximum capacity of the matrix.
1904 //
1905 // \return The capacity of the matrix.
1906 */
1907 template< typename MT  // Type of the adapted dense matrix
1908         , bool SO >    // Storage order of the adapted dense matrix
capacity()1909 inline size_t SymmetricMatrix<MT,SO,true,false>::capacity() const noexcept
1910 {
1911    return matrix_.capacity();
1912 }
1913 /*! \endcond */
1914 //*************************************************************************************************
1915 
1916 
1917 //*************************************************************************************************
1918 /*! \cond BLAZE_INTERNAL */
1919 /*!\brief Returns the current capacity of the specified row/column.
1920 //
1921 // \param i The index of the row/column.
1922 // \return The current capacity of row/column \a i.
1923 //
1924 // This function returns the current capacity of the specified row/column. In case the symmetric
1925 // matrix adapts a \a rowMajor dense matrix the function returns the capacity of row \a i, in
1926 // case it adapts a \a columnMajor dense matrix the function returns the capacity of column \a i.
1927 */
1928 template< typename MT  // Type of the adapted dense matrix
1929         , bool SO >    // Storage order of the adapted dense matrix
capacity(size_t i)1930 inline size_t SymmetricMatrix<MT,SO,true,false>::capacity( size_t i ) const noexcept
1931 {
1932    return matrix_.capacity(i);
1933 }
1934 /*! \endcond */
1935 //*************************************************************************************************
1936 
1937 
1938 //*************************************************************************************************
1939 /*! \cond BLAZE_INTERNAL */
1940 /*!\brief Returns the total number of non-zero elements in the matrix
1941 //
1942 // \return The number of non-zero elements in the symmetric matrix.
1943 */
1944 template< typename MT  // Type of the adapted dense matrix
1945         , bool SO >    // Storage order of the adapted dense matrix
nonZeros()1946 inline size_t SymmetricMatrix<MT,SO,true,false>::nonZeros() const
1947 {
1948    size_t nonzeros( 0UL );
1949 
1950    if( SO )
1951    {
1952       for( size_t j=0UL; j<columns(); ++j ) {
1953          for( size_t i=0UL; i<j; ++i ) {
1954             if( !isDefault( matrix_(i,j) ) )
1955                nonzeros += 2UL;
1956          }
1957          if( !isDefault( matrix_(j,j) ) )
1958             ++nonzeros;
1959       }
1960    }
1961    else
1962    {
1963       for( size_t i=0UL; i<rows(); ++i ) {
1964          for( size_t j=0UL; j<i; ++j ) {
1965             if( !isDefault( matrix_(i,j) ) )
1966                nonzeros += 2UL;
1967          }
1968          if( !isDefault( matrix_(i,i) ) )
1969             ++nonzeros;
1970       }
1971    }
1972 
1973    return nonzeros;
1974 }
1975 /*! \endcond */
1976 //*************************************************************************************************
1977 
1978 
1979 //*************************************************************************************************
1980 /*! \cond BLAZE_INTERNAL */
1981 /*!\brief Returns the number of non-zero elements in the specified row/column.
1982 //
1983 // \param i The index of the row/column.
1984 // \return The number of non-zero elements of row/column \a i.
1985 //
1986 // This function returns the current number of non-zero elements in the specified row/column. In
1987 // case the symmetric matrix adapts a \a rowMajor dense matrix the function returns the number of
1988 // non-zero elements in row \a i, in case it adapts a to \a columnMajor dense matrix the function
1989 // returns the number of non-zero elements in column \a i.
1990 */
1991 template< typename MT  // Type of the adapted dense matrix
1992         , bool SO >    // Storage order of the adapted dense matrix
nonZeros(size_t i)1993 inline size_t SymmetricMatrix<MT,SO,true,false>::nonZeros( size_t i ) const
1994 {
1995    size_t nonzeros( 0UL );
1996 
1997    if( SO )
1998    {
1999       for( size_t j=0UL; j<i; ++j ) {
2000          if( !isDefault( matrix_(j,i) ) )
2001             ++nonzeros;
2002       }
2003       for( size_t j=i; j<rows(); ++j ) {
2004          if( !isDefault( matrix_(i,j) ) )
2005             ++nonzeros;
2006       }
2007    }
2008    else
2009    {
2010       for( size_t j=0UL; j<i; ++j ) {
2011          if( !isDefault( matrix_(i,j) ) )
2012             ++nonzeros;
2013       }
2014       for( size_t j=i; j<rows(); ++j ) {
2015          if( !isDefault( matrix_(j,i) ) )
2016             ++nonzeros;
2017       }
2018    }
2019 
2020    return nonzeros;
2021 }
2022 /*! \endcond */
2023 //*************************************************************************************************
2024 
2025 
2026 //*************************************************************************************************
2027 /*! \cond BLAZE_INTERNAL */
2028 /*!\brief Reset to the default initial values.
2029 //
2030 // \return void
2031 */
2032 template< typename MT  // Type of the adapted dense matrix
2033         , bool SO >    // Storage order of the adapted dense matrix
reset()2034 inline void SymmetricMatrix<MT,SO,true,false>::reset()
2035 {
2036    using blaze::clear;
2037 
2038    if( SO ) {
2039       for( size_t j=0UL; j<columns(); ++j )
2040          for( size_t i=0UL; i<=j; ++i )
2041             clear( matrix_(i,j) );
2042    }
2043    else {
2044       for( size_t i=0UL; i<rows(); ++i )
2045          for( size_t j=0UL; j<=i; ++j )
2046             clear( matrix_(i,j) );
2047    }
2048 }
2049 /*! \endcond */
2050 //*************************************************************************************************
2051 
2052 
2053 //*************************************************************************************************
2054 /*! \cond BLAZE_INTERNAL */
2055 /*!\brief Reset the specified row \b and column to the default initial values.
2056 //
2057 // \param i The index of the row/column.
2058 // \return void
2059 // \exception std::invalid_argument Invalid row/column access index.
2060 //
2061 // This function resets the values in the specified row \b and column to their default value.
2062 // The following example demonstrates this by means of a \f$ 5 \times 5 \f$ symmetric matrix:
2063 
2064    \code
2065    using blaze::DynamicMatrix;
2066    using blaze::StaticVector;
2067    using blaze::SymmetricMatrix;
2068 
2069    SymmetricMatrix< DynamicMatrix< StaticVector<int,1UL> > > A;
2070 
2071    // Initializing the symmetric matrix A to
2072    //
2073    //      ( (    ) (  2 ) (  5 ) ( -4 ) (    ) )
2074    //      ( (  2 ) (  1 ) ( -3 ) (  7 ) (    ) )
2075    //  A = ( (  5 ) ( -3 ) (  8 ) ( -1 ) ( -2 ) )
2076    //      ( ( -4 ) (  7 ) ( -1 ) (    ) ( -6 ) )
2077    //      ( (    ) (  0 ) ( -2 ) ( -6 ) (  1 ) )
2078    // ...
2079 
2080    // Resetting the 1st row/column results in the matrix
2081    //
2082    //      ( (    ) (    ) (  5 ) ( -4 ) (    ) )
2083    //      ( (    ) (    ) (    ) (    ) (    ) )
2084    //  A = ( (  5 ) (    ) (  8 ) ( -1 ) ( -2 ) )
2085    //      ( ( -4 ) (    ) ( -1 ) (    ) ( -6 ) )
2086    //      ( (    ) (    ) ( -2 ) ( -6 ) (  1 ) )
2087    //
2088    A.reset( 1UL );
2089    \endcode
2090 
2091 // Note that the reset() function has no impact on the capacity of the matrix or row/column.
2092 */
2093 template< typename MT  // Type of the adapted dense matrix
2094         , bool SO >    // Storage order of the adapted dense matrix
reset(size_t i)2095 inline void SymmetricMatrix<MT,SO,true,false>::reset( size_t i )
2096 {
2097    using blaze::clear;
2098 
2099    for( auto element=begin(i); element!=end(i); ++element )
2100       clear( *element );
2101 }
2102 /*! \endcond */
2103 //*************************************************************************************************
2104 
2105 
2106 //*************************************************************************************************
2107 /*! \cond BLAZE_INTERNAL */
2108 /*!\brief Clearing the symmetric matrix.
2109 //
2110 // \return void
2111 //
2112 // This function clears the symmetric matrix and returns it to its default state. The function has
2113 // the same effect as calling clear() on the adapted matrix of type \a MT: In case of a resizable
2114 // matrix (for instance DynamicMatrix or HybridMatrix) the number of rows and columns will be set
2115 // to 0, whereas in case of a fixed-size matrix (for instance StaticMatrix) only the elements will
2116 // be reset to their default state.
2117 */
2118 template< typename MT  // Type of the adapted dense matrix
2119         , bool SO >    // Storage order of the adapted dense matrix
clear()2120 inline void SymmetricMatrix<MT,SO,true,false>::clear()
2121 {
2122    using blaze::clear;
2123 
2124    clear( matrix_ );
2125 }
2126 /*! \endcond */
2127 //*************************************************************************************************
2128 
2129 
2130 //*************************************************************************************************
2131 /*! \cond BLAZE_INTERNAL */
2132 /*!\brief Changing the size of the symmetric matrix.
2133 //
2134 // \param n The new number of rows and columns of the matrix.
2135 // \param preserve \a true if the old values of the matrix should be preserved, \a false if not.
2136 // \return void
2137 //
2138 // In case the symmetric matrix adapts a resizable matrix, this function resizes the matrix using
2139 // the given size to \f$ n \times n \f$. During this operation, new dynamic memory may be allocated
2140 // in case the capacity of the matrix is too small. Note that this function may invalidate all
2141 // existing views (submatrices, rows, columns, ...) on the matrix if it is used to shrink the
2142 // matrix. Additionally, the resize operation potentially changes all matrix elements. In order
2143 // to preserve the old matrix values, the \a preserve flag can be set to \a true. In case the
2144 // size of the matrix is increased, new elements are default initialized.
2145 */
2146 template< typename MT  // Type of the adapted dense matrix
2147         , bool SO >    // Storage order of the adapted dense matrix
resize(size_t n,bool preserve)2148 void SymmetricMatrix<MT,SO,true,false>::resize( size_t n, bool preserve )
2149 {
2150    BLAZE_CONSTRAINT_MUST_BE_RESIZABLE_TYPE( MT );
2151 
2152    MAYBE_UNUSED( preserve );
2153 
2154    BLAZE_INTERNAL_ASSERT( isSquare( matrix_ ), "Non-square symmetric matrix detected" );
2155 
2156    const size_t oldsize( matrix_.rows() );
2157 
2158    matrix_.resize( n, n, true );
2159 
2160    if( n > oldsize ) {
2161       const size_t increment( n - oldsize );
2162       submatrix( matrix_, 0UL, oldsize, oldsize, increment ).reset();
2163       submatrix( matrix_, oldsize, 0UL, increment, n ).reset();
2164    }
2165 }
2166 /*! \endcond */
2167 //*************************************************************************************************
2168 
2169 
2170 //*************************************************************************************************
2171 /*! \cond BLAZE_INTERNAL */
2172 /*!\brief Extending the size of the matrix.
2173 //
2174 // \param n Number of additional rows and columns.
2175 // \param preserve \a true if the old values of the matrix should be preserved, \a false if not.
2176 // \return void
2177 //
2178 // This function increases the matrix size by \a n rows and \a n columns. During this operation,
2179 // new dynamic memory may be allocated in case the capacity of the matrix is too small. Therefore
2180 // this function potentially changes all matrix elements. In order to preserve the old matrix
2181 // values, the \a preserve flag can be set to \a true. The new elements are default initialized.
2182 */
2183 template< typename MT  // Type of the adapted dense matrix
2184         , bool SO >    // Storage order of the adapted dense matrix
extend(size_t n,bool preserve)2185 inline void SymmetricMatrix<MT,SO,true,false>::extend( size_t n, bool preserve )
2186 {
2187    BLAZE_CONSTRAINT_MUST_BE_RESIZABLE_TYPE( MT );
2188 
2189    MAYBE_UNUSED( preserve );
2190 
2191    resize( rows() + n, true );
2192 }
2193 /*! \endcond */
2194 //*************************************************************************************************
2195 
2196 
2197 //*************************************************************************************************
2198 /*! \cond BLAZE_INTERNAL */
2199 /*!\brief Setting the minimum capacity of the matrix.
2200 //
2201 // \param elements The new minimum capacity of the symmetric matrix.
2202 // \return void
2203 //
2204 // This function increases the capacity of the symmetric matrix to at least \a elements elements.
2205 // The current values of the matrix elements are preserved.
2206 */
2207 template< typename MT  // Type of the adapted dense matrix
2208         , bool SO >    // Storage order of the adapted dense matrix
reserve(size_t elements)2209 inline void SymmetricMatrix<MT,SO,true,false>::reserve( size_t elements )
2210 {
2211    matrix_.reserve( elements );
2212 }
2213 /*! \endcond */
2214 //*************************************************************************************************
2215 
2216 
2217 //*************************************************************************************************
2218 /*! \cond BLAZE_INTERNAL */
2219 /*!\brief Requesting the removal of unused capacity.
2220 //
2221 // \return void
2222 //
2223 // This function minimizes the capacity of the matrix by removing unused capacity. Please note
2224 // that in case a reallocation occurs, all iterators (including end() iterators), all pointers
2225 // and references to elements of this matrix are invalidated.
2226 */
2227 template< typename MT  // Type of the adapted dense matrix
2228         , bool SO >    // Storage order of the adapted dense matrix
shrinkToFit()2229 inline void SymmetricMatrix<MT,SO,true,false>::shrinkToFit()
2230 {
2231    matrix_.shrinkToFit();
2232 }
2233 /*! \endcond */
2234 //*************************************************************************************************
2235 
2236 
2237 //*************************************************************************************************
2238 /*! \cond BLAZE_INTERNAL */
2239 /*!\brief Swapping the contents of two matrices.
2240 //
2241 // \param m The matrix to be swapped.
2242 // \return void
2243 */
2244 template< typename MT  // Type of the adapted dense matrix
2245         , bool SO >    // Storage order of the adapted dense matrix
swap(SymmetricMatrix & m)2246 inline void SymmetricMatrix<MT,SO,true,false>::swap( SymmetricMatrix& m ) noexcept
2247 {
2248    using std::swap;
2249 
2250    swap( matrix_, m.matrix_ );
2251 }
2252 /*! \endcond */
2253 //*************************************************************************************************
2254 
2255 
2256 
2257 
2258 //=================================================================================================
2259 //
2260 //  NUMERIC FUNCTIONS
2261 //
2262 //=================================================================================================
2263 
2264 //*************************************************************************************************
2265 /*! \cond BLAZE_INTERNAL */
2266 /*!\brief In-place transpose of the symmetric matrix.
2267 //
2268 // \return Reference to the transposed matrix.
2269 */
2270 template< typename MT  // Type of the adapted dense matrix
2271         , bool SO >    // Storage order of the adapted dense matrix
transpose()2272 inline SymmetricMatrix<MT,SO,true,false>& SymmetricMatrix<MT,SO,true,false>::transpose()
2273 {
2274    return *this;
2275 }
2276 /*! \endcond */
2277 //*************************************************************************************************
2278 
2279 
2280 //*************************************************************************************************
2281 /*! \cond BLAZE_INTERNAL */
2282 /*!\brief In-place conjugate transpose of the symmetric matrix.
2283 //
2284 // \return Reference to the transposed matrix.
2285 */
2286 template< typename MT  // Type of the adapted dense matrix
2287         , bool SO >    // Storage order of the adapted dense matrix
ctranspose()2288 inline SymmetricMatrix<MT,SO,true,false>& SymmetricMatrix<MT,SO,true,false>::ctranspose()
2289 {
2290    if( SO ) {
2291       for( size_t j=0UL; j<columns(); ++j )
2292          for( size_t i=0UL; i<=j; ++i )
2293             conjugate( matrix_(i,j) );
2294    }
2295    else {
2296       for( size_t i=0UL; i<rows(); ++i )
2297          for( size_t j=0UL; j<=i; ++j )
2298             conjugate( matrix_(i,j) );
2299    }
2300 
2301    return *this;
2302 }
2303 /*! \endcond */
2304 //*************************************************************************************************
2305 
2306 
2307 //*************************************************************************************************
2308 /*! \cond BLAZE_INTERNAL */
2309 /*!\brief Scaling of the matrix by the scalar value \a scalar (\f$ A=B*s \f$).
2310 //
2311 // \param scalar The scalar value for the matrix scaling.
2312 // \return Reference to the matrix.
2313 //
2314 // This function scales the matrix by applying the given scalar value \a scalar to each element
2315 // of the matrix. For built-in and \c complex data types it has the same effect as using the
2316 // multiplication assignment operator:
2317 
2318    \code
2319    blaze::SymmetricMatrix< blaze::DynamicMatrix< blaze::StaticVector<int,1UL> > > A;
2320    // ... Resizing and initialization
2321    A *= 4;        // Scaling of the matrix
2322    A.scale( 4 );  // Same effect as above
2323    \endcode
2324 */
2325 template< typename MT       // Type of the adapted dense matrix
2326         , bool SO >         // Storage order of the adapted dense matrix
2327 template< typename Other >  // Data type of the scalar value
2328 inline SymmetricMatrix<MT,SO,true,false>&
scale(const Other & scalar)2329    SymmetricMatrix<MT,SO,true,false>::scale( const Other& scalar )
2330 {
2331    if( SO ) {
2332       for( size_t j=0UL; j<columns(); ++j )
2333          for( size_t i=0UL; i<=j; ++i )
2334             matrix_(i,j) *= scalar;
2335    }
2336    else {
2337       for( size_t i=0UL; i<rows(); ++i )
2338          for( size_t j=0UL; j<=i; ++j )
2339             matrix_(i,j) *= scalar;
2340    }
2341 
2342    return *this;
2343 }
2344 /*! \endcond */
2345 //*************************************************************************************************
2346 
2347 
2348 
2349 
2350 //=================================================================================================
2351 //
2352 //  DEBUGGING FUNCTIONS
2353 //
2354 //=================================================================================================
2355 
2356 //*************************************************************************************************
2357 /*! \cond BLAZE_INTERNAL */
2358 /*!\brief Returns whether the invariants of the symmetric matrix are intact.
2359 //
2360 // \return \a true in case the symmetric matrix's invariants are intact, \a false otherwise.
2361 //
2362 // This function checks whether the invariants of the symmetric matrix are intact, i.e. if its
2363 // state is valid. In case the invariants are intact, the function returns \a true, else it
2364 // will return \a false.
2365 */
2366 template< typename MT  // Type of the adapted dense matrix
2367         , bool SO >    // Storage order of the adapted dense matrix
isIntact()2368 inline bool SymmetricMatrix<MT,SO,true,false>::isIntact() const noexcept
2369 {
2370    using blaze::isIntact;
2371 
2372    return isIntact( matrix_ ) &&
2373           ( IsCustom_v<MT> || ( SO ? isUpper( matrix_ ) : isLower( matrix_ ) ) );
2374 }
2375 /*! \endcond */
2376 //*************************************************************************************************
2377 
2378 
2379 
2380 
2381 //=================================================================================================
2382 //
2383 //  EXPRESSION TEMPLATE EVALUATION FUNCTIONS
2384 //
2385 //=================================================================================================
2386 
2387 //*************************************************************************************************
2388 /*! \cond BLAZE_INTERNAL */
2389 /*!\brief Returns whether the matrix can alias with the given address \a alias.
2390 //
2391 // \param alias The alias to be checked.
2392 // \return \a true in case the alias corresponds to this matrix, \a false if not.
2393 //
2394 // This function returns whether the given address can alias with the matrix. In contrast
2395 // to the isAliased() function this function is allowed to use compile time expressions
2396 // to optimize the evaluation.
2397 */
2398 template< typename MT       // Type of the adapted dense matrix
2399         , bool SO >         // Storage order of the adapted dense matrix
2400 template< typename Other >  // Data type of the foreign expression
canAlias(const Other * alias)2401 inline bool SymmetricMatrix<MT,SO,true,false>::canAlias( const Other* alias ) const noexcept
2402 {
2403    return matrix_.canAlias( alias );
2404 }
2405 /*! \endcond */
2406 //*************************************************************************************************
2407 
2408 
2409 //*************************************************************************************************
2410 /*! \cond BLAZE_INTERNAL */
2411 /*!\brief Returns whether the matrix is aliased with the given address \a alias.
2412 //
2413 // \param alias The alias to be checked.
2414 // \return \a true in case the alias corresponds to this matrix, \a false if not.
2415 //
2416 // This function returns whether the given address is aliased with the matrix. In contrast
2417 // to the canAlias() function this function is not allowed to use compile time expressions
2418 // to optimize the evaluation.
2419 */
2420 template< typename MT       // Type of the adapted dense matrix
2421         , bool SO >         // Storage order of the adapted dense matrix
2422 template< typename Other >  // Data type of the foreign expression
isAliased(const Other * alias)2423 inline bool SymmetricMatrix<MT,SO,true,false>::isAliased( const Other* alias ) const noexcept
2424 {
2425    return matrix_.isAliased( alias );
2426 }
2427 /*! \endcond */
2428 //*************************************************************************************************
2429 
2430 
2431 //*************************************************************************************************
2432 /*! \cond BLAZE_INTERNAL */
2433 /*!\brief Returns whether the matrix is properly aligned in memory.
2434 //
2435 // \return \a true in case the matrix is aligned, \a false if not.
2436 //
2437 // This function returns whether the matrix is guaranteed to be properly aligned in memory, i.e.
2438 // whether the beginning and the end of each row/column of the matrix are guaranteed to conform
2439 // to the alignment restrictions of the element type \a Type.
2440 */
2441 template< typename MT  // Type of the adapted dense matrix
2442         , bool SO >    // Storage order of the adapted dense matrix
isAligned()2443 inline bool SymmetricMatrix<MT,SO,true,false>::isAligned() const noexcept
2444 {
2445    return matrix_.isAligned();
2446 }
2447 /*! \endcond */
2448 //*************************************************************************************************
2449 
2450 
2451 //*************************************************************************************************
2452 /*! \cond BLAZE_INTERNAL */
2453 /*!\brief Returns whether the matrix can be used in SMP assignments.
2454 //
2455 // \return \a true in case the matrix can be used in SMP assignments, \a false if not.
2456 //
2457 // This function returns whether the matrix can be used in SMP assignments. In contrast to the
2458 // \a smpAssignable member enumeration, which is based solely on compile time information, this
2459 // function additionally provides runtime information (as for instance the current number of
2460 // rows and/or columns of the matrix).
2461 */
2462 template< typename MT  // Type of the adapted dense matrix
2463         , bool SO >    // Storage order of the adapted dense matrix
canSMPAssign()2464 inline bool SymmetricMatrix<MT,SO,true,false>::canSMPAssign() const noexcept
2465 {
2466    return matrix_.canSMPAssign();
2467 }
2468 /*! \endcond */
2469 //*************************************************************************************************
2470 
2471 
2472 //*************************************************************************************************
2473 /*! \cond BLAZE_INTERNAL */
2474 /*!\brief Optimized implementation of the assignment of a temporary dense matrix.
2475 //
2476 // \param rhs The right-hand side dense matrix to be assigned.
2477 // \return void
2478 //
2479 // This function must \b NOT be called explicitly! It is used internally for the performance
2480 // optimized evaluation of expression templates. Calling this function explicitly might result
2481 // in erroneous results and/or in compilation errors. Instead of using this function use the
2482 // assignment operator.
2483 */
2484 template< typename MT     // Type of the adapted dense matrix
2485         , bool SO >       // Storage order of the adapted dense matrix
2486 template< typename MT2 >  // Type of the right-hand side dense matrix
assign(DenseMatrix<MT2,SO> & rhs)2487 inline void SymmetricMatrix<MT,SO,true,false>::assign( DenseMatrix<MT2,SO>& rhs )
2488 {
2489    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2490    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2491 
2492    if( SO ) {
2493       for( size_t j=0UL; j<columns(); ++j )
2494          for( size_t i=0UL; i<=j; ++i )
2495             matrix_(i,j) = std::move( (*rhs)(i,j) );
2496    }
2497    else {
2498       for( size_t i=0UL; i<rows(); ++i )
2499          for( size_t j=0UL; j<=i; ++j )
2500             matrix_(i,j) = std::move( (*rhs)(i,j) );
2501    }
2502 }
2503 /*! \endcond */
2504 //*************************************************************************************************
2505 
2506 
2507 //*************************************************************************************************
2508 /*! \cond BLAZE_INTERNAL */
2509 /*!\brief Default implementation of the assignment of a dense matrix.
2510 //
2511 // \param rhs The right-hand side dense matrix to be assigned.
2512 // \return void
2513 //
2514 // This function must \b NOT be called explicitly! It is used internally for the performance
2515 // optimized evaluation of expression templates. Calling this function explicitly might result
2516 // in erroneous results and/or in compilation errors. Instead of using this function use the
2517 // assignment operator.
2518 */
2519 template< typename MT     // Type of the adapted dense matrix
2520         , bool SO >       // Storage order of the adapted dense matrix
2521 template< typename MT2 >  // Type of the right-hand side dense matrix
assign(const DenseMatrix<MT2,SO> & rhs)2522 inline void SymmetricMatrix<MT,SO,true,false>::assign( const DenseMatrix<MT2,SO>& rhs )
2523 {
2524    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2525    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2526 
2527    if( SO ) {
2528       for( size_t j=0UL; j<columns(); ++j )
2529          for( size_t i=0UL; i<=j; ++i )
2530             matrix_(i,j) = (*rhs)(i,j);
2531    }
2532    else {
2533       for( size_t i=0UL; i<rows(); ++i )
2534          for( size_t j=0UL; j<=i; ++j )
2535             matrix_(i,j) = (*rhs)(i,j);
2536    }
2537 }
2538 /*! \endcond */
2539 //*************************************************************************************************
2540 
2541 
2542 //*************************************************************************************************
2543 /*! \cond BLAZE_INTERNAL */
2544 /*!\brief Default implementation of the assignment of a sparse matrix.
2545 //
2546 // \param rhs The right-hand side sparse matrix to be assigned.
2547 // \return void
2548 //
2549 // This function must \b NOT be called explicitly! It is used internally for the performance
2550 // optimized evaluation of expression templates. Calling this function explicitly might result
2551 // in erroneous results and/or in compilation errors. Instead of using this function use the
2552 // assignment operator.
2553 */
2554 template< typename MT     // Type of the adapted dense matrix
2555         , bool SO >       // Storage order of the adapted dense matrix
2556 template< typename MT2 >  // Type of the right-hand side sparse matrix
assign(const SparseMatrix<MT2,SO> & rhs)2557 inline void SymmetricMatrix<MT,SO,true,false>::assign( const SparseMatrix<MT2,SO>& rhs )
2558 {
2559    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2560    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2561 
2562    if( SO ) {
2563       for( size_t j=0UL; j<columns(); ++j ) {
2564          const auto last( (*rhs).upperBound(j,j) );
2565          for( auto element=(*rhs).begin(j); element!=last; ++element )
2566             matrix_(element->index(),j) = element->value();
2567       }
2568    }
2569    else {
2570       for( size_t i=0UL; i<rows(); ++i ) {
2571          const auto last( (*rhs).upperBound(i,i) );
2572          for( auto element=(*rhs).begin(i); element!=last; ++element )
2573             matrix_(i,element->index()) = element->value();
2574       }
2575    }
2576 }
2577 /*! \endcond */
2578 //*************************************************************************************************
2579 
2580 
2581 //*************************************************************************************************
2582 /*! \cond BLAZE_INTERNAL */
2583 /*!\brief Default implementation of the addition assignment of a dense matrix.
2584 //
2585 // \param rhs The right-hand side dense matrix to be added.
2586 // \return void
2587 //
2588 // This function must \b NOT be called explicitly! It is used internally for the performance
2589 // optimized evaluation of expression templates. Calling this function explicitly might result
2590 // in erroneous results and/or in compilation errors. Instead of using this function use the
2591 // assignment operator.
2592 */
2593 template< typename MT     // Type of the adapted dense matrix
2594         , bool SO >       // Storage order of the adapted dense matrix
2595 template< typename MT2 >  // Type of the right-hand side dense matrix
addAssign(const DenseMatrix<MT2,SO> & rhs)2596 inline void SymmetricMatrix<MT,SO,true,false>::addAssign( const DenseMatrix<MT2,SO>& rhs )
2597 {
2598    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2599    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2600 
2601    if( SO ) {
2602       for( size_t j=0UL; j<columns(); ++j )
2603          for( size_t i=0UL; i<=j; ++i )
2604             matrix_(i,j) += (*rhs)(i,j);
2605    }
2606    else {
2607       for( size_t i=0UL; i<rows(); ++i )
2608          for( size_t j=0UL; j<=i; ++j )
2609             matrix_(i,j) += (*rhs)(i,j);
2610    }
2611 }
2612 /*! \endcond */
2613 //*************************************************************************************************
2614 
2615 
2616 //*************************************************************************************************
2617 /*! \cond BLAZE_INTERNAL */
2618 /*!\brief Default implementation of the addition assignment of a sparse matrix.
2619 //
2620 // \param rhs The right-hand side sparse matrix to be added.
2621 // \return void
2622 //
2623 // This function must \b NOT be called explicitly! It is used internally for the performance
2624 // optimized evaluation of expression templates. Calling this function explicitly might result
2625 // in erroneous results and/or in compilation errors. Instead of using this function use the
2626 // assignment operator.
2627 */
2628 template< typename MT     // Type of the adapted dense matrix
2629         , bool SO >       // Storage order of the adapted dense matrix
2630 template< typename MT2 >  // Type of the right-hand side sparse matrix
addAssign(const SparseMatrix<MT2,SO> & rhs)2631 inline void SymmetricMatrix<MT,SO,true,false>::addAssign( const SparseMatrix<MT2,SO>& rhs )
2632 {
2633    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2634    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2635 
2636    if( SO ) {
2637       for( size_t j=0UL; j<columns(); ++j ) {
2638          const auto last( (*rhs).upperBound(j,j) );
2639          for( auto element=(*rhs).begin(j); element!=last; ++element )
2640             matrix_(element->index(),j) += element->value();
2641       }
2642    }
2643    else {
2644       for( size_t i=0UL; i<rows(); ++i ) {
2645          const auto last( (*rhs).upperBound(i,i) );
2646          for( auto element=(*rhs).begin(i); element!=last; ++element )
2647             matrix_(i,element->index()) += element->value();
2648       }
2649    }
2650 }
2651 /*! \endcond */
2652 //*************************************************************************************************
2653 
2654 
2655 //*************************************************************************************************
2656 /*! \cond BLAZE_INTERNAL */
2657 /*!\brief Default implementation of the subtraction assignment of a dense matrix.
2658 //
2659 // \param rhs The right-hand side dense matrix to be subtracted.
2660 // \return void
2661 //
2662 // This function must \b NOT be called explicitly! It is used internally for the performance
2663 // optimized evaluation of expression templates. Calling this function explicitly might result
2664 // in erroneous results and/or in compilation errors. Instead of using this function use the
2665 // assignment operator.
2666 */
2667 template< typename MT     // Type of the adapted dense matrix
2668         , bool SO >       // Storage order of the adapted dense matrix
2669 template< typename MT2 >  // Type of the right-hand side dense matrix
subAssign(const DenseMatrix<MT2,SO> & rhs)2670 inline void SymmetricMatrix<MT,SO,true,false>::subAssign( const DenseMatrix<MT2,SO>& rhs )
2671 {
2672    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2673    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2674 
2675    if( SO ) {
2676       for( size_t j=0UL; j<columns(); ++j )
2677          for( size_t i=0UL; i<=j; ++i )
2678             matrix_(i,j) -= (*rhs)(i,j);
2679    }
2680    else {
2681       for( size_t i=0UL; i<rows(); ++i )
2682          for( size_t j=0UL; j<=i; ++j )
2683             matrix_(i,j) -= (*rhs)(i,j);
2684    }
2685 }
2686 /*! \endcond */
2687 //*************************************************************************************************
2688 
2689 
2690 //*************************************************************************************************
2691 /*! \cond BLAZE_INTERNAL */
2692 /*!\brief Default implementation of the subtraction assignment of a sparse matrix.
2693 //
2694 // \param rhs The right-hand side sparse matrix to be subtracted.
2695 // \return void
2696 //
2697 // This function must \b NOT be called explicitly! It is used internally for the performance
2698 // optimized evaluation of expression templates. Calling this function explicitly might result
2699 // in erroneous results and/or in compilation errors. Instead of using this function use the
2700 // assignment operator.
2701 */
2702 template< typename MT     // Type of the adapted dense matrix
2703         , bool SO >       // Storage order of the adapted dense matrix
2704 template< typename MT2 >  // Type of the right-hand side sparse matrix
subAssign(const SparseMatrix<MT2,SO> & rhs)2705 inline void SymmetricMatrix<MT,SO,true,false>::subAssign( const SparseMatrix<MT2,SO>& rhs )
2706 {
2707    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2708    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2709 
2710    if( SO ) {
2711       for( size_t j=0UL; j<columns(); ++j ) {
2712          const auto last( (*rhs).upperBound(j,j) );
2713          for( auto element=(*rhs).begin(j); element!=last; ++element )
2714             matrix_(element->index(),j) -= element->value();
2715       }
2716    }
2717    else {
2718       for( size_t i=0UL; i<rows(); ++i ) {
2719          const auto last( (*rhs).upperBound(i,i) );
2720          for( auto element=(*rhs).begin(i); element!=last; ++element )
2721             matrix_(i,element->index()) -= element->value();
2722       }
2723    }
2724 }
2725 /*! \endcond */
2726 //*************************************************************************************************
2727 
2728 
2729 //*************************************************************************************************
2730 /*! \cond BLAZE_INTERNAL */
2731 /*!\brief Default implementation of the Schur product assignment of a dense matrix.
2732 //
2733 // \param rhs The right-hand side dense matrix for the Schur product.
2734 // \return void
2735 //
2736 // This function must \b NOT be called explicitly! It is used internally for the performance
2737 // optimized evaluation of expression templates. Calling this function explicitly might result
2738 // in erroneous results and/or in compilation errors. Instead of using this function use the
2739 // assignment operator.
2740 */
2741 template< typename MT     // Type of the adapted dense matrix
2742         , bool SO >       // Storage order of the adapted dense matrix
2743 template< typename MT2 >  // Type of the right-hand side dense matrix
schurAssign(const DenseMatrix<MT2,SO> & rhs)2744 inline void SymmetricMatrix<MT,SO,true,false>::schurAssign( const DenseMatrix<MT2,SO>& rhs )
2745 {
2746    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2747    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2748 
2749    if( SO ) {
2750       for( size_t j=0UL; j<columns(); ++j )
2751          for( size_t i=0UL; i<=j; ++i )
2752             matrix_(i,j) *= (*rhs)(i,j);
2753    }
2754    else {
2755       for( size_t i=0UL; i<rows(); ++i )
2756          for( size_t j=0UL; j<=i; ++j )
2757             matrix_(i,j) *= (*rhs)(i,j);
2758    }
2759 }
2760 /*! \endcond */
2761 //*************************************************************************************************
2762 
2763 
2764 //*************************************************************************************************
2765 /*! \cond BLAZE_INTERNAL */
2766 /*!\brief Default implementation of the Schur product assignment of a sparse matrix.
2767 //
2768 // \param rhs The right-hand side sparse matrix for the Schur product.
2769 // \return void
2770 //
2771 // This function must \b NOT be called explicitly! It is used internally for the performance
2772 // optimized evaluation of expression templates. Calling this function explicitly might result
2773 // in erroneous results and/or in compilation errors. Instead of using this function use the
2774 // assignment operator.
2775 */
2776 template< typename MT     // Type of the adapted dense matrix
2777         , bool SO >       // Storage order of the adapted dense matrix
2778 template< typename MT2 >  // Type of the right-hand side sparse matrix
schurAssign(const SparseMatrix<MT2,SO> & rhs)2779 inline void SymmetricMatrix<MT,SO,true,false>::schurAssign( const SparseMatrix<MT2,SO>& rhs )
2780 {
2781    BLAZE_INTERNAL_ASSERT( rows()    == (*rhs).rows()   , "Invalid number of rows"    );
2782    BLAZE_INTERNAL_ASSERT( columns() == (*rhs).columns(), "Invalid number of columns" );
2783 
2784    if( SO ) {
2785       for( size_t j=0UL; j<columns(); ++j )
2786       {
2787          size_t i( 0UL );
2788 
2789          const auto last( (*rhs).upperBound(j,j) );
2790          for( auto element=(*rhs).begin(j); element!=last; ++element ) {
2791             for( ; i<element->index(); ++i )
2792                reset( matrix_(i,j) );
2793             matrix_(i,j) *= element->value();
2794             ++i;
2795          }
2796 
2797          for( ; i<rows(); ++i ) {
2798             reset( matrix_(i,j) );
2799          }
2800       }
2801    }
2802    else {
2803       for( size_t i=0UL; i<rows(); ++i )
2804       {
2805          size_t j( 0UL );
2806 
2807          const auto last( (*rhs).upperBound(i,i) );
2808          for( auto element=(*rhs).begin(i); element!=last; ++element ) {
2809             for( ; j<element->index(); ++j )
2810                reset( matrix_(i,j) );
2811             matrix_(i,j) *= element->value();
2812             ++j;
2813          }
2814 
2815          for( ; j<columns(); ++j ) {
2816             reset( matrix_(i,j) );
2817          }
2818       }
2819    }
2820 }
2821 /*! \endcond */
2822 //*************************************************************************************************
2823 
2824 } // namespace blaze
2825 
2826 #endif
2827