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