Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/math/statistics/sequencestatistics.hpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2003, 2004, 2005, 2006, 2007 Ferdinando Ametrano
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <http://quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
/*! \file sequencestatistics.hpp
21
    \brief Statistics tools for sequence (vector, list, array) samples
22
*/
23
24
#ifndef quantlib_sequence_statistics_hpp
25
#define quantlib_sequence_statistics_hpp
26
27
#include <ql/math/statistics/statistics.hpp>
28
#include <ql/math/statistics/incrementalstatistics.hpp>
29
#include <ql/math/matrix.hpp>
30
31
namespace QuantLib {
32
33
    //! Statistics analysis of N-dimensional (sequence) data
34
    /*! It provides 1-dimensional statistics as discrepancy plus
35
        N-dimensional (sequence) statistics (e.g. mean,
36
        variance, skewness, kurtosis, etc.) with one component for each
37
        dimension of the sample space.
38
39
        For most of the statistics this class relies on
40
        the StatisticsType underlying class to provide 1-D methods that
41
        will be iterated for all the components of the N-D data. These
42
        lifted methods are the union of all the methods that might be
43
        requested to the 1-D underlying StatisticsType class, with the
44
        usual compile-time checks provided by the template approach.
45
46
        \test the correctness of the returned values is tested by
47
              checking them against numerical calculations.
48
    */
49
    template <class StatisticsType>
50
    class GenericSequenceStatistics {
51
      public:
52
        // typedefs
53
        typedef StatisticsType statistics_type;
54
        typedef std::vector<typename StatisticsType::value_type> value_type;
55
        // constructor
56
        GenericSequenceStatistics(Size dimension = 0);
57
        //! \name inspectors
58
        //@{
59
        Size size() const { return dimension_; }
60
        //@}
61
        //! \name covariance and correlation
62
        //@{
63
        //! returns the covariance Matrix
64
        Matrix covariance() const;
65
        //! returns the correlation Matrix
66
        Matrix correlation() const;
67
        //@}
68
        //! \name 1-D inspectors lifted from underlying statistics class
69
        //@{
70
        Size samples() const;
71
        Real weightSum() const;
72
        //@}
73
        //! \name N-D inspectors lifted from underlying statistics class
74
        //@{
75
        // void argument list
76
        std::vector<Real> mean() const;
77
        std::vector<Real> variance() const;
78
        std::vector<Real> standardDeviation() const;
79
        std::vector<Real> downsideVariance() const;
80
        std::vector<Real> downsideDeviation() const;
81
        std::vector<Real> semiVariance() const;
82
        std::vector<Real> semiDeviation() const;
83
        std::vector<Real> errorEstimate() const;
84
        std::vector<Real> skewness() const;
85
        std::vector<Real> kurtosis() const;
86
        std::vector<Real> min() const;
87
        std::vector<Real> max() const;
88
89
        // single argument list
90
        std::vector<Real> gaussianPercentile(Real y) const;
91
        std::vector<Real> percentile(Real y) const;
92
93
        std::vector<Real> gaussianPotentialUpside(Real percentile) const;
94
        std::vector<Real> potentialUpside(Real percentile) const;
95
96
        std::vector<Real> gaussianValueAtRisk(Real percentile) const;
97
        std::vector<Real> valueAtRisk(Real percentile) const;
98
99
        std::vector<Real> gaussianExpectedShortfall(Real percentile) const;
100
        std::vector<Real> expectedShortfall(Real percentile) const;
101
102
        std::vector<Real> regret(Real target) const;
103
104
        std::vector<Real> gaussianShortfall(Real target) const;
105
        std::vector<Real> shortfall(Real target) const;
106
107
        std::vector<Real> gaussianAverageShortfall(Real target) const;
108
        std::vector<Real> averageShortfall(Real target) const;
109
110
        //@}
111
        //! \name Modifiers
112
        //@{
113
        void reset(Size dimension = 0);
114
        template <class Sequence>
115
        void add(const Sequence& sample,
116
0
                 Real weight = 1.0) {
117
0
            add(sample.begin(), sample.end(), weight);
118
0
        }
Unexecuted instantiation: void QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::add<std::__1::vector<double, std::__1::allocator<double> > >(std::__1::vector<double, std::__1::allocator<double> > const&, double)
Unexecuted instantiation: void QuantLib::GenericSequenceStatistics<QuantLib::IncrementalStatistics>::add<std::__1::vector<double, std::__1::allocator<double> > >(std::__1::vector<double, std::__1::allocator<double> > const&, double)
119
        template <class Iterator>
120
        void add(Iterator begin,
121
                 Iterator end,
122
0
                 Real weight = 1.0) {
123
0
            if (dimension_ == 0) {
124
                // stat wasn't initialized yet
125
0
                QL_REQUIRE(end>begin, "sample error: end<=begin");
126
0
                Size dimension = std::distance(begin, end);
127
0
                reset(dimension);
128
0
            }
129
130
0
            QL_REQUIRE(std::distance(begin, end) == Integer(dimension_),
131
0
                       "sample size mismatch: " << dimension_ <<
132
0
                       " required, " << std::distance(begin, end) <<
133
0
                       " provided");
134
135
0
            quadraticSum_ += weight * outerProduct(begin, end,
136
0
                                                   begin, end);
137
138
0
            for (Size i=0; i<dimension_; ++begin, ++i)
139
0
                stats_[i].add(*begin, weight);
140
141
0
        }
Unexecuted instantiation: void QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::add<std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, double)
Unexecuted instantiation: void QuantLib::GenericSequenceStatistics<QuantLib::IncrementalStatistics>::add<std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*>, double)
Unexecuted instantiation: void QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::add<std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*>, double)
142
        //@}
143
      protected:
144
        Size dimension_ = 0;
145
        std::vector<statistics_type> stats_;
146
        mutable std::vector<Real> results_;
147
        Matrix quadraticSum_;
148
    };
149
150
    //! default multi-dimensional statistics tool
151
    /*! \test the correctness of the returned values is tested by
152
              checking them against numerical calculations.
153
    */
154
    typedef GenericSequenceStatistics<Statistics> SequenceStatistics;
155
    typedef GenericSequenceStatistics<IncrementalStatistics> SequenceStatisticsInc;
156
157
    // inline definitions
158
159
    template <class Stat>
160
0
    inline GenericSequenceStatistics<Stat>::GenericSequenceStatistics(Size dimension) {
161
0
        reset(dimension);
162
0
    }
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::GenericSequenceStatistics(unsigned long)
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::IncrementalStatistics>::GenericSequenceStatistics(unsigned long)
163
164
    template <class Stat>
165
0
    inline Size GenericSequenceStatistics<Stat>::samples() const {
166
0
        return (stats_.empty()) ? 0 : stats_[0].samples();
167
0
    }
168
169
    template <class Stat>
170
0
    inline Real GenericSequenceStatistics<Stat>::weightSum() const {
171
0
        return (stats_.empty()) ? 0.0 : stats_[0].weightSum();
172
0
    }
173
174
175
    // macros for the implementation of the lifted methods
176
177
    // N-D methods' definition with void argument list
178
    #define DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(METHOD) \
179
    template <class Stat> \
180
    std::vector<Real> \
181
0
    GenericSequenceStatistics<Stat>::METHOD() const { \
182
0
        for (Size i=0; i<dimension_; i++) \
183
0
            results_[i] = stats_[i].METHOD(); \
184
0
        return results_; \
185
0
    }
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::mean() const
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::IncrementalStatistics>::mean() const
186
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(mean)
187
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(variance)
188
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(standardDeviation)
189
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(downsideVariance)
190
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(downsideDeviation)
191
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(semiVariance)
192
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(semiDeviation)
193
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(errorEstimate)
194
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(skewness)
195
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(kurtosis)
196
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(min)
197
    DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID(max)
198
    #undef DEFINE_SEQUENCE_STAT_CONST_METHOD_VOID
199
200
201
    // N-D methods' definition with single argument
202
    #define DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(METHOD) \
203
    template <class Stat> \
204
    std::vector<Real> \
205
    GenericSequenceStatistics<Stat>::METHOD(Real x) const { \
206
        for (Size i=0; i<dimension_; i++) \
207
            results_[i] = stats_[i].METHOD(x); \
208
        return results_; \
209
    }
210
211
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianPercentile)
212
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianPotentialUpside)
213
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianValueAtRisk)
214
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianExpectedShortfall)
215
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianShortfall)
216
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(gaussianAverageShortfall)
217
218
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(percentile)
219
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(potentialUpside)
220
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(valueAtRisk)
221
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(expectedShortfall)
222
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(regret)
223
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(shortfall)
224
    DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE(averageShortfall)
225
    #undef DEFINE_SEQUENCE_STAT_CONST_METHOD_DOUBLE
226
227
228
    template <class Stat>
229
0
    void GenericSequenceStatistics<Stat>::reset(Size dimension) {
230
        // (re-)initialize
231
0
        if (dimension > 0) {
232
0
            if (dimension == dimension_) {
233
0
                for (Size i=0; i<dimension_; ++i)
234
0
                    stats_[i].reset();
235
0
            } else {
236
0
                dimension_ = dimension;
237
0
                stats_ = std::vector<Stat>(dimension);
238
0
                results_ = std::vector<Real>(dimension);
239
0
            }
240
0
            quadraticSum_ = Matrix(dimension_, dimension_, 0.0);
241
0
        } else {
242
0
            dimension_ = dimension;
243
0
        }
244
0
    }
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::GenericRiskStatistics<QuantLib::GenericGaussianStatistics<QuantLib::GeneralStatistics> > >::reset(unsigned long)
Unexecuted instantiation: QuantLib::GenericSequenceStatistics<QuantLib::IncrementalStatistics>::reset(unsigned long)
245
246
    template <class Stat>
247
0
    Matrix GenericSequenceStatistics<Stat>::covariance() const {
248
0
        Real sampleWeight = weightSum();
249
0
        QL_REQUIRE(sampleWeight > 0.0,
250
0
                   "sampleWeight=0, unsufficient");
251
252
0
        Real sampleNumber = static_cast<Real>(samples());
253
0
        QL_REQUIRE(sampleNumber > 1.0,
254
0
                   "sample number <=1, unsufficient");
255
256
0
        std::vector<Real> m = mean();
257
0
        Real inv = 1.0/sampleWeight;
258
259
0
        Matrix result = inv*quadraticSum_;
260
0
        result -= outerProduct(m.begin(), m.end(),
261
0
                               m.begin(), m.end());
262
263
0
        result *= (sampleNumber/(sampleNumber-1.0));
264
0
        return result;
265
0
    }
266
267
268
    template <class Stat>
269
    Matrix GenericSequenceStatistics<Stat>::correlation() const {
270
        Matrix correlation = covariance();
271
        Array variances = correlation.diagonal();
272
        for (Size i=0; i<dimension_; i++){
273
            for (Size j=0; j<dimension_; j++){
274
                if (i==j) {
275
                    if (variances[i]==0.0) {
276
                        correlation[i][j] = 1.0;
277
                    } else {
278
                        correlation[i][j] *=
279
                            1.0/std::sqrt(variances[i]*variances[j]);
280
                    }
281
                } else {
282
                    if (variances[i]==0.0 && variances[j]==0) {
283
                        correlation[i][j] = 1.0;
284
                    } else if (variances[i]==0.0 || variances[j]==0.0) {
285
                        correlation[i][j] = 0.0;
286
                    } else {
287
                        correlation[i][j] *=
288
                            1.0/std::sqrt(variances[i]*variances[j]);
289
                    }
290
                }
291
            } // j for
292
        } // i for
293
294
        return correlation;
295
    }
296
297
}
298
299
300
#endif