1 //=================================================================================================
2 /*!
3 // \file blaze/math/expressions/SMatNormExpr.h
4 // \brief Header file for the sparse matrix norm expression
5 //
6 // Copyright (C) 2012-2020 Klaus Iglberger - All Rights Reserved
7 //
8 // This file is part of the Blaze library. You can redistribute it and/or modify it under
9 // the terms of the New (Revised) BSD License. Redistribution and use in source and binary
10 // forms, with or without modification, are permitted provided that the following conditions
11 // are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this list of
14 // conditions and the following disclaimer.
15 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
16 // of conditions and the following disclaimer in the documentation and/or other materials
17 // provided with the distribution.
18 // 3. Neither the names of the Blaze development group nor the names of its contributors
19 // may be used to endorse or promote products derived from this software without specific
20 // prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 */
33 //=================================================================================================
34
35 #ifndef _BLAZE_MATH_EXPRESSIONS_SMATNORMEXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_SMATNORMEXPR_H_
37
38
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42
43 #include <utility>
44 #include <blaze/math/Aliases.h>
45 #include <blaze/math/expressions/SparseMatrix.h>
46 #include <blaze/math/functors/Abs.h>
47 #include <blaze/math/functors/Bind2nd.h>
48 #include <blaze/math/functors/Cbrt.h>
49 #include <blaze/math/functors/L1Norm.h>
50 #include <blaze/math/functors/L2Norm.h>
51 #include <blaze/math/functors/L3Norm.h>
52 #include <blaze/math/functors/L4Norm.h>
53 #include <blaze/math/functors/LpNorm.h>
54 #include <blaze/math/functors/Noop.h>
55 #include <blaze/math/functors/Pow.h>
56 #include <blaze/math/functors/Pow2.h>
57 #include <blaze/math/functors/Pow3.h>
58 #include <blaze/math/functors/Qdrt.h>
59 #include <blaze/math/functors/SqrAbs.h>
60 #include <blaze/math/functors/Sqrt.h>
61 #include <blaze/math/shims/Evaluate.h>
62 #include <blaze/math/shims/Invert.h>
63 #include <blaze/math/shims/IsDefault.h>
64 #include <blaze/math/shims/IsZero.h>
65 #include <blaze/math/traits/MultTrait.h>
66 #include <blaze/math/typetraits/IsResizable.h>
67 #include <blaze/math/typetraits/IsRowMajorMatrix.h>
68 #include <blaze/math/typetraits/UnderlyingBuiltin.h>
69 #include <blaze/util/Assert.h>
70 #include <blaze/util/FunctionTrace.h>
71 #include <blaze/util/StaticAssert.h>
72 #include <blaze/util/TypeList.h>
73 #include <blaze/util/Types.h>
74 #include <blaze/util/typetraits/RemoveCVRef.h>
75
76
77 namespace blaze {
78
79 //=================================================================================================
80 //
81 // GLOBAL FUNCTIONS
82 //
83 //=================================================================================================
84
85 //*************************************************************************************************
86 /*! \cond BLAZE_INTERNAL */
87 /*!\brief Default backend implementation of the norm of a sparse matrix.
88 // \ingroup sparse_matrix
89 //
90 // \param sm The given sparse matrix for the norm computation.
91 // \param abs The functor for the abs operation.
92 // \param power The functor for the power operation.
93 // \param root The functor for the root operation.
94 // \return The norm of the given matrix.
95 //
96 // This function implements the performance optimized norm of a sparse matrix. Due to the
97 // explicit application of the SFINAE principle, this function can only be selected by the
98 // compiler in case vectorization cannot be applied.
99 */
100 template< typename MT // Type of the sparse matrix
101 , bool SO // Storage order
102 , typename Abs // Type of the abs operation
103 , typename Power // Type of the power operation
104 , typename Root > // Type of the root operation
decltype(auto)105 inline decltype(auto) norm_backend( const SparseMatrix<MT,SO>& sm, Abs abs, Power power, Root root )
106 {
107 using CT = CompositeType_t<MT>;
108 using ET = ElementType_t<MT>;
109 using PT = RemoveCVRef_t< decltype( power( abs( std::declval<ET>() ) ) ) >;
110 using RT = RemoveCVRef_t< decltype( evaluate( root( std::declval<PT>() ) ) ) >;
111
112 if( (*sm).rows() == 0UL || (*sm).columns() == 0UL ) return RT{};
113
114 CT tmp( *sm );
115
116 const size_t N( IsRowMajorMatrix_v<MT> ? tmp.rows(): tmp.columns() );
117
118 PT norm{};
119
120 for( size_t i=0UL; i<N; ++i )
121 {
122 const auto end( tmp.end(i) );
123 for( auto element=tmp.begin(i); element!=end; ++element ) {
124 if( IsResizable_v<ET> && isDefault( norm ) )
125 norm = power( abs( element->value() ) );
126 else
127 norm += power( abs( element->value() ) );
128 }
129 }
130
131 return evaluate( root( norm ) );
132 }
133 /*! \endcond */
134 //*************************************************************************************************
135
136
137 //*************************************************************************************************
138 /*!\brief Computes the L2 norm for the given sparse matrix.
139 // \ingroup sparse_matrix
140 //
141 // \param sm The given sparse matrix for the norm computation.
142 // \return The L2 norm of the given sparse matrix.
143 //
144 // This function computes the L2 norm of the given sparse matrix:
145
146 \code
147 blaze::CompressedMatrix<double> A;
148 // ... Resizing and initialization
149 const double l2 = norm( A );
150 \endcode
151 */
152 template< typename MT // Type of the sparse matrix
153 , bool SO > // Storage order
decltype(auto)154 decltype(auto) norm( const SparseMatrix<MT,SO>& sm )
155 {
156 BLAZE_FUNCTION_TRACE;
157
158 return norm_backend( *sm, SqrAbs(), Noop(), Sqrt() );
159 }
160 //*************************************************************************************************
161
162
163 //*************************************************************************************************
164 /*!\brief Computes the squared L2 norm for the given sparse matrix.
165 // \ingroup sparse_matrix
166 //
167 // \param sm The given sparse matrix for the norm computation.
168 // \return The squared L2 norm of the given sparse matrix.
169 //
170 // This function computes the squared L2 norm of the given sparse matrix:
171
172 \code
173 blaze::CompressedMatrix<double> A;
174 // ... Resizing and initialization
175 const double l2 = sqrNorm( A );
176 \endcode
177 */
178 template< typename MT // Type of the sparse matrix
179 , bool SO > // Storage order
decltype(auto)180 decltype(auto) sqrNorm( const SparseMatrix<MT,SO>& sm )
181 {
182 BLAZE_FUNCTION_TRACE;
183
184 return norm_backend( *sm, SqrAbs(), Noop(), Noop() );
185 }
186 //*************************************************************************************************
187
188
189 //*************************************************************************************************
190 /*!\brief Computes the L1 norm for the given sparse matrix.
191 // \ingroup sparse_matrix
192 //
193 // \param sm The given sparse matrix for the norm computation.
194 // \return The L1 norm of the given sparse matrix.
195 //
196 // This function computes the L1 norm of the given sparse matrix:
197
198 \code
199 blaze::CompressedMatrix<double> A;
200 // ... Resizing and initialization
201 const double l1 = l1Norm( A );
202 \endcode
203 */
204 template< typename MT // Type of the sparse matrix
205 , bool SO > // Storage order
decltype(auto)206 decltype(auto) l1Norm( const SparseMatrix<MT,SO>& sm )
207 {
208 BLAZE_FUNCTION_TRACE;
209
210 return norm_backend( *sm, Abs(), Noop(), Noop() );
211 }
212 //*************************************************************************************************
213
214
215 //*************************************************************************************************
216 /*!\brief Computes the L2 norm for the given sparse matrix.
217 // \ingroup sparse_matrix
218 //
219 // \param sm The given sparse matrix for the norm computation.
220 // \return The L2 norm of the given sparse matrix.
221 //
222 // This function computes the L2 norm of the given sparse matrix:
223
224 \code
225 blaze::CompressedMatrix<double> A;
226 // ... Resizing and initialization
227 const double l2 = l2Norm( A );
228 \endcode
229 */
230 template< typename MT // Type of the sparse matrix
231 , bool SO > // Storage order
decltype(auto)232 decltype(auto) l2Norm( const SparseMatrix<MT,SO>& sm )
233 {
234 BLAZE_FUNCTION_TRACE;
235
236 return norm_backend( *sm, SqrAbs(), Noop(), Sqrt() );
237 }
238 //*************************************************************************************************
239
240
241 //*************************************************************************************************
242 /*!\brief Computes the L3 norm for the given sparse matrix.
243 // \ingroup sparse_matrix
244 //
245 // \param sm The given sparse matrix for the norm computation.
246 // \return The L3 norm of the given sparse matrix.
247 //
248 // This function computes the L3 norm of the given sparse matrix:
249
250 \code
251 blaze::CompressedMatrix<double> A;
252 // ... Resizing and initialization
253 const double l3 = l3Norm( A );
254 \endcode
255 */
256 template< typename MT // Type of the sparse matrix
257 , bool SO > // Storage order
decltype(auto)258 decltype(auto) l3Norm( const SparseMatrix<MT,SO>& sm )
259 {
260 BLAZE_FUNCTION_TRACE;
261
262 return norm_backend( *sm, Abs(), Pow3(), Cbrt() );
263 }
264 //*************************************************************************************************
265
266
267 //*************************************************************************************************
268 /*!\brief Computes the L4 norm for the given sparse matrix.
269 // \ingroup sparse_matrix
270 //
271 // \param sm The given sparse matrix for the norm computation.
272 // \return The L4 norm of the given sparse matrix.
273 //
274 // This function computes the L4 norm of the given sparse matrix:
275
276 \code
277 blaze::CompressedMatrix<double> A;
278 // ... Resizing and initialization
279 const double l4 = l4Norm( A );
280 \endcode
281 */
282 template< typename MT // Type of the sparse matrix
283 , bool SO > // Storage order
decltype(auto)284 decltype(auto) l4Norm( const SparseMatrix<MT,SO>& sm )
285 {
286 BLAZE_FUNCTION_TRACE;
287
288 return norm_backend( *sm, SqrAbs(), Pow2(), Qdrt() );
289 }
290 //*************************************************************************************************
291
292
293 //*************************************************************************************************
294 /*!\brief Computes the Lp norm for the given sparse matrix.
295 // \ingroup sparse_matrix
296 //
297 // \param sm The given sparse matrix for the norm computation.
298 // \param p The norm parameter (p > 0).
299 // \return The Lp norm of the given sparse matrix.
300 //
301 // This function computes the Lp norm of the given sparse matrix, where the norm is specified by
302 // the runtime argument \a p:
303
304 \code
305 blaze::CompressedMatrix<double> A;
306 // ... Resizing and initialization
307 const double lp = lpNorm( A, 2.3 );
308 \endcode
309
310 // \note The norm parameter \a p is expected to be larger than 0. This precondition is only checked
311 // by a user assertion.
312 */
313 template< typename MT // Type of the sparse matrix
314 , bool SO // Storage order
315 , typename ST > // Type of the norm parameter
decltype(auto)316 decltype(auto) lpNorm( const SparseMatrix<MT,SO>& sm, ST p )
317 {
318 BLAZE_FUNCTION_TRACE;
319
320 BLAZE_USER_ASSERT( !isZero( p ), "Invalid p for Lp norm detected" );
321
322 using ScalarType = MultTrait_t< UnderlyingBuiltin_t<MT>, decltype( inv( p ) ) >;
323 using UnaryPow = Bind2nd<Pow,ScalarType>;
324 return norm_backend( *sm, Abs(), UnaryPow( Pow(), p ), UnaryPow( Pow(), inv( p ) ) );
325 }
326 //*************************************************************************************************
327
328
329 //*************************************************************************************************
330 /*!\brief Computes the Lp norm for the given sparse matrix.
331 // \ingroup sparse_matrix
332 //
333 // \param sm The given sparse matrix for the norm computation.
334 // \return The Lp norm of the given sparse matrix.
335 //
336 // This function computes the Lp norm of the given sparse matrix, where the norm is specified by
337 // the runtime argument \a P:
338
339 \code
340 blaze::CompressedMatrix<double> A;
341 // ... Resizing and initialization
342 const double lp = lpNorm<2>( A );
343 \endcode
344
345 // \note The norm parameter \a P is expected to be larger than 0. A value of 0 results in a
346 // compile time error!.
347 */
348 template< size_t P // Compile time norm parameter
349 , typename MT // Type of the sparse matrix
350 , bool SO > // Storage order
decltype(auto)351 inline decltype(auto) lpNorm( const SparseMatrix<MT,SO>& sm )
352 {
353 BLAZE_STATIC_ASSERT_MSG( P > 0UL, "Invalid norm parameter detected" );
354
355 using Norms = TypeList< L1Norm, L2Norm, L3Norm, L4Norm, LpNorm<P> >;
356 using Norm = typename TypeAt< Norms, min( P-1UL, 4UL ) >::Type;
357
358 return Norm()( *sm );
359 }
360 //*************************************************************************************************
361
362
363 //*************************************************************************************************
364 /*!\brief Computes the infinity norm for the given sparse matrix.
365 // \ingroup sparse_matrix
366 //
367 // \param sm The given sparse matrix for the norm computation.
368 // \return The infinity norm of the given sparse matrix.
369 //
370 // This function computes the infinity norm of the given sparse matrix:
371
372 \code
373 blaze::CompressedMatrix<double> A;
374 // ... Resizing and initialization
375 const double linf = linfNorm( A );
376 \endcode
377 */
378 template< typename MT // Type of the sparse matrix
379 , bool SO > // Storage order
decltype(auto)380 decltype(auto) linfNorm( const SparseMatrix<MT,SO>& sm )
381 {
382 BLAZE_FUNCTION_TRACE;
383
384 return max( abs( *sm ) );
385 }
386 //*************************************************************************************************
387
388
389 //*************************************************************************************************
390 /*!\brief Computes the maximum norm for the given sparse matrix.
391 // \ingroup sparse_matrix
392 //
393 // \param sm The given sparse matrix for the norm computation.
394 // \return The maximum norm of the given sparse matrix.
395 //
396 // This function computes the maximum norm of the given sparse matrix:
397
398 \code
399 blaze::CompressedMatrix<double> A;
400 // ... Resizing and initialization
401 const double max = maxNorm( A );
402 \endcode
403 */
404 template< typename MT // Type of the sparse matrix
405 , bool SO > // Storage order
decltype(auto)406 decltype(auto) maxNorm( const SparseMatrix<MT,SO>& sm )
407 {
408 BLAZE_FUNCTION_TRACE;
409
410 return linfNorm( *sm );
411 }
412 //*************************************************************************************************
413
414 } // namespace blaze
415
416 #endif
417