1 //=================================================================================================
2 /*!
3 //  \file blaze/math/expressions/DMatVarExpr.h
4 //  \brief Header file for the dense matrix variance 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_DMATVAREXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_DMATVAREXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
43 #include <blaze/math/Exception.h>
44 #include <blaze/math/dense/UniformMatrix.h>
45 #include <blaze/math/dense/UniformVector.h>
46 #include <blaze/math/expressions/DenseMatrix.h>
47 #include <blaze/math/functors/Pow2.h>
48 #include <blaze/math/ReductionFlag.h>
49 #include <blaze/math/shims/Invert.h>
50 #include <blaze/math/typetraits/IsUniform.h>
51 #include <blaze/math/typetraits/UnderlyingBuiltin.h>
52 #include <blaze/util/FunctionTrace.h>
53 #include <blaze/util/IntegralConstant.h>
54 #include <blaze/util/MaybeUnused.h>
55 #include <blaze/util/StaticAssert.h>
56 #include <blaze/util/Types.h>
57 
58 
59 namespace blaze {
60 
61 //=================================================================================================
62 //
63 //  GLOBAL FUNCTIONS
64 //
65 //=================================================================================================
66 
67 //*************************************************************************************************
68 /*! \cond BLAZE_INTERNAL */
69 /*!\brief Backend implementation of the \c var() function for general dense matrices.
70 // \ingroup dense_matrix
71 //
72 // \param dm The given general dense matrix for the variance computation.
73 // \return The variance of the given matrix.
74 */
75 template< typename MT  // Type of the dense matrix
76         , bool SO >    // Storage order
decltype(auto)77 inline decltype(auto) var_backend( const DenseMatrix<MT,SO>& dm, FalseType )
78 {
79    using BT = UnderlyingBuiltin_t<MT>;
80 
81    BLAZE_INTERNAL_ASSERT( size( *dm ) > 1UL, "Invalid matrix size detected" );
82 
83    const auto m( uniform<SO>( rows( *dm ), columns( *dm ), mean( *dm ) ) );
84 
85    return sum( map( (*dm) - m, Pow2() ) ) * inv( BT( size( *dm )-1UL ) );
86 }
87 /*! \endcond */
88 //*************************************************************************************************
89 
90 
91 //*************************************************************************************************
92 /*! \cond BLAZE_INTERNAL */
93 /*!\brief Backend implementation of the \c var() function for uniform dense matrices.
94 // \ingroup dense_matrix
95 //
96 // \param dm The given uniform dense matrix for the variance computation.
97 // \return The var of the given matrix.
98 */
99 template< typename MT  // Type of the dense matrix
100         , bool SO >    // Storage order
decltype(auto)101 inline decltype(auto) var_backend( const DenseMatrix<MT,SO>& dm, TrueType )
102 {
103    MAYBE_UNUSED( dm );
104 
105    BLAZE_INTERNAL_ASSERT( size( *dm ) > 1UL, "Invalid matrix size detected" );
106 
107    return ElementType_t<MT>();
108 }
109 /*! \endcond */
110 //*************************************************************************************************
111 
112 
113 //*************************************************************************************************
114 /*!\brief Computes the variance for the given dense matrix.
115 // \ingroup dense_matrix
116 //
117 // \param dm The given dense matrix for the variance computation.
118 // \return The variance of the given matrix.
119 // \exception std::invalid_argument Invalid input matrix.
120 //
121 // This function computes the <a href="https://en.wikipedia.org/wiki/Variance">variance</a> for
122 // the given dense matrix \a dm. Example:
123 
124    \code
125    using blaze::DynamicMatrix;
126 
127    DynamicMatrix<int> A{ { 1, 3, 2 }
128                        , { 2, 6, 4 }
129                        , { 9, 6, 3 } };
130 
131    const double v = var( A );  // Results in 6.5
132    \endcode
133 
134 // In case the size of the given matrix is smaller than 2, a \a std::invalid_argument is thrown.
135 */
136 template< typename MT  // Type of the dense matrix
137         , bool SO >    // Storage order
decltype(auto)138 inline decltype(auto) var( const DenseMatrix<MT,SO>& dm )
139 {
140    BLAZE_FUNCTION_TRACE;
141 
142    if( size( *dm ) < 2UL ) {
143       BLAZE_THROW_INVALID_ARGUMENT( "Invalid input matrix" );
144    }
145 
146    return var_backend( *dm, IsUniform<MT>() );
147 }
148 //*************************************************************************************************
149 
150 
151 //*************************************************************************************************
152 /*! \cond BLAZE_INTERNAL */
153 /*!\brief Backend implementation of the row-/column-wise \c var() function for general dense matrices.
154 // \ingroup dense_matrix
155 //
156 // \param dm The given general dense matrix for the variance computation.
157 // \return The row-/column-wise variance of the given matrix.
158 */
159 template< ReductionFlag RF  // Reduction flag
160         , typename MT       // Type of the dense matrix
161         , bool SO >         // Storage order
decltype(auto)162 decltype(auto) var_backend( const DenseMatrix<MT,SO>& dm, FalseType )
163 {
164    using BT = UnderlyingBuiltin_t<MT>;
165 
166    const size_t n( RF == rowwise ? columns( *dm ) : rows( *dm ) );
167 
168    BLAZE_INTERNAL_ASSERT( n > 1UL, "Invalid matrix size detected" );
169 
170    const auto m( expand( mean<RF>( *dm ), n ) );
171 
172    return sum<RF>( map( (*dm) - m, Pow2() ) ) * inv( BT( n-1UL ) );
173 }
174 /*! \endcond */
175 //*************************************************************************************************
176 
177 
178 //*************************************************************************************************
179 /*! \cond BLAZE_INTERNAL */
180 /*!\brief Backend implementation of the row-/column-wise \c var() function for uniform dense matrices.
181 // \ingroup dense_matrix
182 //
183 // \param dm The given general dense matrix for the variance computation.
184 // \return The row-/column-wise variance of the given matrix.
185 */
186 template< ReductionFlag RF  // Reduction flag
187         , typename MT       // Type of the dense matrix
188         , bool SO >         // Storage order
decltype(auto)189 decltype(auto) var_backend( const DenseMatrix<MT,SO>& dm, TrueType )
190 {
191    const size_t n( RF == rowwise ? rows( *dm ) : columns( *dm ) );
192 
193    BLAZE_INTERNAL_ASSERT( n > 0UL, "Invalid matrix size detected" );
194 
195    constexpr bool TF( ( RF == rowwise ? columnVector : rowVector ) );
196 
197    return uniform<TF>( n, ElementType_t<MT>() );
198 }
199 /*! \endcond */
200 //*************************************************************************************************
201 
202 
203 //*************************************************************************************************
204 /*!\brief Computes the row-/column-wise variance function for the given dense matrix.
205 // \ingroup dense_matrix
206 //
207 // \param dm The given dense matrix for the variance computation.
208 // \return The row-/column-wise variance of the given matrix.
209 // \exception std::invalid_argument Invalid input matrix.
210 //
211 // This function computes the row-/column-wise
212 // <a href="https://en.wikipedia.org/wiki/Variance">variance</a> for the given dense matrix
213 // \a dm. In case \a RF is set to \a rowwise, the function returns a column vector containing
214 // the variance of each row of \a dm. In case \a RF is set to \a columnwise, the function
215 // returns a row vector containing the variance of each column of \a dm. Example:
216 
217    \code
218    using blaze::DynamicMatrix;
219    using blaze::DynamicVector;
220    using blaze::columnVector;
221    using blaze::rowVector;
222 
223    DynamicMatrix<int> A{ { 1, 3, 2 }
224                        , { 2, 6, 4 }
225                        , { 9, 6, 3 } };
226 
227    DynamicVector<double,columnVector> rv;
228    DynamicVector<double,rowVector> cv;
229 
230    rv = var<rowwise>( A );     // Results in ( 1  4  9 )
231    cv = var<columnwise>( A );  // Results in ( 19  3  1 )
232    \endcode
233 
234 // In case \a RF is set to \a rowwise and the number of columns of the given matrix is smaller
235 // than 2 or in case \a RF is set to \a columnwise and the number of rows of the given matrix is
236 // smaller than 2, a \a std::invalid_argument is thrown.
237 */
238 template< ReductionFlag RF  // Reduction flag
239         , typename MT       // Type of the dense matrix
240         , bool SO >         // Storage order
decltype(auto)241 inline decltype(auto) var( const DenseMatrix<MT,SO>& dm )
242 {
243    BLAZE_FUNCTION_TRACE;
244 
245    BLAZE_STATIC_ASSERT_MSG( RF < 2UL, "Invalid reduction flag" );
246 
247    const size_t n( RF == rowwise ? columns( *dm ) : rows( *dm ) );
248 
249    if( n < 2UL ) {
250       BLAZE_THROW_INVALID_ARGUMENT( "Invalid input matrix" );
251    }
252 
253    return var_backend<RF>( *dm, IsUniform<MT>() );
254 }
255 //*************************************************************************************************
256 
257 } // namespace blaze
258 
259 #endif
260