1 //=================================================================================================
2 /*!
3 //  \file blaze/math/HybridMatrix.h
4 //  \brief Header file for the complete HybridMatrix implementation
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_HYBRIDMATRIX_H_
36 #define _BLAZE_MATH_HYBRIDMATRIX_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <blaze/math/constraints/Scalar.h>
44 #include <blaze/math/dense/HybridMatrix.h>
45 #include <blaze/math/DenseMatrix.h>
46 #include <blaze/math/Exception.h>
47 #include <blaze/math/HybridVector.h>
48 #include <blaze/math/IdentityMatrix.h>
49 #include <blaze/math/shims/Conjugate.h>
50 #include <blaze/math/shims/Real.h>
51 #include <blaze/math/StaticMatrix.h>
52 #include <blaze/math/typetraits/UnderlyingBuiltin.h>
53 #include <blaze/math/ZeroMatrix.h>
54 #include <blaze/util/Assert.h>
55 #include <blaze/util/Random.h>
56 
57 
58 namespace blaze {
59 
60 //=================================================================================================
61 //
62 //  RAND SPECIALIZATION
63 //
64 //=================================================================================================
65 
66 //*************************************************************************************************
67 /*! \cond BLAZE_INTERNAL */
68 /*!\brief Specialization of the Rand class template for HybridMatrix.
69 // \ingroup random
70 //
71 // This specialization of the Rand class creates random instances of HybridMatrix.
72 */
73 template< typename Type     // Data type of the matrix
74         , size_t M          // Number of rows
75         , size_t N          // Number of columns
76         , bool SO           // Storage order
77         , AlignmentFlag AF  // Alignment flag
78         , PaddingFlag PF    // Padding flag
79         , typename Tag >    // Type tag
80 class Rand< HybridMatrix<Type,M,N,SO,AF,PF,Tag> >
81 {
82  public:
83    //*************************************************************************************************
84    /*!\brief Generation of a random HybridMatrix.
85    //
86    // \return The generated random matrix.
87    */
88    inline const HybridMatrix<Type,M,N,SO,AF,PF,Tag>
generate(size_t m,size_t n)89       generate( size_t m, size_t n ) const
90    {
91       HybridMatrix<Type,M,N,SO,AF,PF,Tag> matrix( m, n );
92       randomize( matrix );
93       return matrix;
94    }
95    //*************************************************************************************************
96 
97    //*************************************************************************************************
98    /*!\brief Generation of a random HybridMatrix.
99    //
100    // \param min The smallest possible value for a matrix element.
101    // \param max The largest possible value for a matrix element.
102    // \return The generated random matrix.
103    */
104    template< typename Arg >    // Min/max argument type
105    inline const HybridMatrix<Type,M,N,SO,AF,PF,Tag>
generate(size_t m,size_t n,const Arg & min,const Arg & max)106       generate( size_t m, size_t n, const Arg& min, const Arg& max ) const
107    {
108       HybridMatrix<Type,M,N,SO,AF,PF,Tag> matrix( m, n );
109       randomize( matrix, min, max );
110       return matrix;
111    }
112    //*************************************************************************************************
113 
114    //*************************************************************************************************
115    /*!\brief Randomization of a HybridMatrix.
116    //
117    // \param matrix The matrix to be randomized.
118    // \return void
119    */
randomize(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix)120    inline void randomize( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix ) const
121    {
122       using blaze::randomize;
123 
124       const size_t m( matrix.rows()    );
125       const size_t n( matrix.columns() );
126 
127       for( size_t i=0UL; i<m; ++i ) {
128          for( size_t j=0UL; j<n; ++j ) {
129             randomize( matrix(i,j) );
130          }
131       }
132    }
133    //*************************************************************************************************
134 
135    //*************************************************************************************************
136    /*!\brief Randomization of a HybridMatrix.
137    //
138    // \param matrix The matrix to be randomized.
139    // \param min The smallest possible value for a matrix element.
140    // \param max The largest possible value for a matrix element.
141    // \return void
142    */
143    template< typename Arg >  // Min/max argument type
randomize(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix,const Arg & min,const Arg & max)144    inline void randomize( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix,
145                           const Arg& min, const Arg& max ) const
146    {
147       using blaze::randomize;
148 
149       const size_t m( matrix.rows()    );
150       const size_t n( matrix.columns() );
151 
152       for( size_t i=0UL; i<m; ++i ) {
153          for( size_t j=0UL; j<n; ++j ) {
154             randomize( matrix(i,j), min, max );
155          }
156       }
157    }
158    //*************************************************************************************************
159 };
160 /*! \endcond */
161 //*************************************************************************************************
162 
163 
164 
165 
166 //=================================================================================================
167 //
168 //  MAKE FUNCTIONS
169 //
170 //=================================================================================================
171 
172 //*************************************************************************************************
173 /*! \cond BLAZE_INTERNAL */
174 /*!\brief Setup of a random symmetric HybridMatrix.
175 //
176 // \param matrix The matrix to be randomized.
177 // \return void
178 // \exception std::invalid_argument Invalid non-square matrix provided.
179 */
180 template< typename Type     // Data type of the matrix
181         , size_t M          // Number of rows
182         , size_t N          // Number of columns
183         , bool SO           // Storage order
184         , AlignmentFlag AF  // Alignment flag
185         , PaddingFlag PF    // Padding flag
186         , typename Tag >    // Type tag
makeSymmetric(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix)187 void makeSymmetric( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix )
188 {
189    using blaze::randomize;
190 
191    if( !isSquare( *matrix ) ) {
192       BLAZE_THROW_INVALID_ARGUMENT( "Invalid non-square matrix provided" );
193    }
194 
195    const size_t n( matrix.rows() );
196 
197    for( size_t i=0UL; i<n; ++i ) {
198       for( size_t j=0UL; j<i; ++j ) {
199          randomize( matrix(i,j) );
200          matrix(j,i) = matrix(i,j);
201       }
202       randomize( matrix(i,i) );
203    }
204 
205    BLAZE_INTERNAL_ASSERT( isSymmetric( matrix ), "Non-symmetric matrix detected" );
206 }
207 /*! \endcond */
208 //*************************************************************************************************
209 
210 
211 //*************************************************************************************************
212 /*! \cond BLAZE_INTERNAL */
213 /*!\brief Setup of a random symmetric HybridMatrix.
214 //
215 // \param matrix The matrix to be randomized.
216 // \param min The smallest possible value for a matrix element.
217 // \param max The largest possible value for a matrix element.
218 // \return void
219 // \exception std::invalid_argument Invalid non-square matrix provided.
220 */
221 template< typename Type     // Data type of the matrix
222         , size_t M          // Number of rows
223         , size_t N          // Number of columns
224         , bool SO           // Storage order
225         , AlignmentFlag AF  // Alignment flag
226         , PaddingFlag PF    // Padding flag
227         , typename Tag      // Type tag
228         , typename Arg >    // Min/max argument type
makeSymmetric(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix,const Arg & min,const Arg & max)229 void makeSymmetric( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix, const Arg& min, const Arg& max )
230 {
231    using blaze::randomize;
232 
233    if( !isSquare( *matrix ) ) {
234       BLAZE_THROW_INVALID_ARGUMENT( "Invalid non-square matrix provided" );
235    }
236 
237    const size_t n( matrix.rows() );
238 
239    for( size_t i=0UL; i<n; ++i ) {
240       for( size_t j=0UL; j<i; ++j ) {
241          randomize( matrix(i,j), min, max );
242          matrix(j,i) = matrix(i,j);
243       }
244       randomize( matrix(i,i), min, max );
245    }
246 
247    BLAZE_INTERNAL_ASSERT( isSymmetric( matrix ), "Non-symmetric matrix detected" );
248 }
249 /*! \endcond */
250 //*************************************************************************************************
251 
252 
253 //*************************************************************************************************
254 /*! \cond BLAZE_INTERNAL */
255 /*!\brief Setup of a random Hermitian HybridMatrix.
256 //
257 // \param matrix The matrix to be randomized.
258 // \return void
259 // \exception std::invalid_argument Invalid non-square matrix provided.
260 */
261 template< typename Type     // Data type of the matrix
262         , size_t M          // Number of rows
263         , size_t N          // Number of columns
264         , bool SO           // Storage order
265         , AlignmentFlag AF  // Alignment flag
266         , PaddingFlag PF    // Padding flag
267         , typename Tag >    // Type tag
makeHermitian(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix)268 void makeHermitian( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix )
269 {
270    using blaze::randomize;
271 
272    BLAZE_CONSTRAINT_MUST_BE_SCALAR_TYPE( Type );
273 
274    using BT = UnderlyingBuiltin_t<Type>;
275 
276    if( !isSquare( *matrix ) ) {
277       BLAZE_THROW_INVALID_ARGUMENT( "Invalid non-square matrix provided" );
278    }
279 
280    const size_t n( matrix.rows() );
281 
282    for( size_t i=0UL; i<n; ++i ) {
283       for( size_t j=0UL; j<i; ++j ) {
284          randomize( matrix(i,j) );
285          matrix(j,i) = conj( matrix(i,j) );
286       }
287       matrix(i,i) = rand<BT>();
288    }
289 
290    BLAZE_INTERNAL_ASSERT( isHermitian( matrix ), "Non-Hermitian matrix detected" );
291 }
292 /*! \endcond */
293 //*************************************************************************************************
294 
295 
296 //*************************************************************************************************
297 /*! \cond BLAZE_INTERNAL */
298 /*!\brief Setup of a random Hermitian HybridMatrix.
299 //
300 // \param matrix The matrix to be randomized.
301 // \param min The smallest possible value for a matrix element.
302 // \param max The largest possible value for a matrix element.
303 // \return void
304 // \exception std::invalid_argument Invalid non-square matrix provided.
305 */
306 template< typename Type     // Data type of the matrix
307         , size_t M          // Number of rows
308         , size_t N          // Number of columns
309         , bool SO           // Storage order
310         , AlignmentFlag AF  // Alignment flag
311         , PaddingFlag PF    // Padding flag
312         , typename Tag      // Type tag
313         , typename Arg >    // Min/max argument type
makeHermitian(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix,const Arg & min,const Arg & max)314 void makeHermitian( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix, const Arg& min, const Arg& max )
315 {
316    using blaze::randomize;
317 
318    BLAZE_CONSTRAINT_MUST_BE_SCALAR_TYPE( Type );
319 
320    using BT = UnderlyingBuiltin_t<Type>;
321 
322    if( !isSquare( *matrix ) ) {
323       BLAZE_THROW_INVALID_ARGUMENT( "Invalid non-square matrix provided" );
324    }
325 
326    const size_t n( matrix.rows() );
327 
328    for( size_t i=0UL; i<n; ++i ) {
329       for( size_t j=0UL; j<i; ++j ) {
330          randomize( matrix(i,j), min, max );
331          matrix(j,i) = conj( matrix(i,j) );
332       }
333       matrix(i,i) = rand<BT>( real( min ), real( max ) );
334    }
335 
336    BLAZE_INTERNAL_ASSERT( isHermitian( matrix ), "Non-Hermitian matrix detected" );
337 }
338 /*! \endcond */
339 //*************************************************************************************************
340 
341 
342 //*************************************************************************************************
343 /*! \cond BLAZE_INTERNAL */
344 /*!\brief Setup of a random (Hermitian) positive definite HybridMatrix.
345 //
346 // \param matrix The matrix to be randomized.
347 // \return void
348 // \exception std::invalid_argument Invalid non-square matrix provided.
349 */
350 template< typename Type     // Data type of the matrix
351         , size_t M          // Number of rows
352         , size_t N          // Number of columns
353         , bool SO           // Storage order
354         , AlignmentFlag AF  // Alignment flag
355         , PaddingFlag PF    // Padding flag
356         , typename Tag >    // Type tag
makePositiveDefinite(HybridMatrix<Type,M,N,SO,AF,PF,Tag> & matrix)357 void makePositiveDefinite( HybridMatrix<Type,M,N,SO,AF,PF,Tag>& matrix )
358 {
359    using blaze::randomize;
360 
361    BLAZE_CONSTRAINT_MUST_BE_SCALAR_TYPE( Type );
362 
363    if( !isSquare( *matrix ) ) {
364       BLAZE_THROW_INVALID_ARGUMENT( "Invalid non-square matrix provided" );
365    }
366 
367    const size_t n( matrix.rows() );
368 
369    randomize( matrix );
370    matrix *= ctrans( matrix );
371 
372    for( size_t i=0UL; i<n; ++i ) {
373       matrix(i,i) += Type(n);
374    }
375 
376    BLAZE_INTERNAL_ASSERT( isHermitian( matrix ), "Non-symmetric matrix detected" );
377 }
378 /*! \endcond */
379 //*************************************************************************************************
380 
381 } // namespace blaze
382 
383 #endif
384