Coverage Report

Created: 2025-08-11 06:28

/src/quantlib/ql/math/generallinearleastsquares.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) 2009 Dirk Eddelbuettel
5
 Copyright (C) 2006, 2009, 2010 Klaus Spanderen
6
 Copyright (C) 2010 Kakhkhor Abdijalilov
7
 Copyright (C) 2010 Slava Mazur
8
9
 This file is part of QuantLib, a free-software/open-source library
10
 for financial quantitative analysts and developers - http://quantlib.org/
11
12
 QuantLib is free software: you can redistribute it and/or modify it
13
 under the terms of the QuantLib license.  You should have received a
14
 copy of the license along with this program; if not, please email
15
 <quantlib-dev@lists.sf.net>. The license is also available online at
16
 <http://quantlib.org/license.shtml>.
17
18
 This program is distributed in the hope that it will be useful, but WITHOUT
19
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 FOR A PARTICULAR PURPOSE.  See the license for more details.
21
*/
22
23
/*! \file generallinearleastsquares.hpp
24
    \brief general linear least square regression
25
*/
26
27
#ifndef quantlib_general_linear_least_squares_hpp
28
#define quantlib_general_linear_least_squares_hpp
29
30
#include <ql/qldefines.hpp>
31
#include <ql/math/matrixutilities/svd.hpp>
32
#include <ql/math/array.hpp>
33
#include <vector>
34
35
namespace QuantLib {
36
37
    //! general linear least squares regression
38
    /*! References:
39
    "Numerical Recipes in C", 2nd edition,
40
    Press, Teukolsky, Vetterling, Flannery,
41
42
    \test the correctness of the returned values is tested by
43
    checking their properties.
44
    */
45
    class GeneralLinearLeastSquares {
46
    public:
47
        template <class xContainer, class yContainer, class vContainer>
48
        GeneralLinearLeastSquares(const xContainer & x,
49
                                  const yContainer & y, const vContainer & v);
50
51
        template<class xIterator, class yIterator, class vIterator>
52
        GeneralLinearLeastSquares(xIterator xBegin, xIterator xEnd,
53
                                  yIterator yBegin, yIterator yEnd,
54
                                  vIterator vBegin, vIterator vEnd);
55
56
0
        const Array& coefficients()   const { return a_; }
57
0
        const Array& residuals()      const { return residuals_; }
58
59
        //! standard parameter errors as given by Excel, R etc.
60
0
        const Array& standardErrors() const { return standardErrors_; }
61
        //! modeling uncertainty as definied in Numerical Recipes
62
0
        const Array& error()          const { return err_;}
63
64
0
        Size size() const { return residuals_.size(); }
65
66
0
        Size dim() const { return a_.size(); }
67
68
    protected:
69
        Array a_, err_, residuals_, standardErrors_;
70
71
        template <class xIterator, class yIterator, class vIterator>
72
        void calculate(
73
            xIterator xBegin, xIterator xEnd,
74
            yIterator yBegin, yIterator yEnd,
75
            vIterator vBegin);
76
    };
77
78
    template <class xContainer, class yContainer, class vContainer> inline
79
    GeneralLinearLeastSquares::GeneralLinearLeastSquares(const xContainer & x,
80
                                                         const yContainer & y,
81
                                                         const vContainer & v)
82
0
    : a_(v.size(), 0.0),
83
0
      err_(v.size(), 0.0),
84
0
      residuals_(y.size()),
85
0
      standardErrors_(v.size()) {
86
0
        calculate(x.begin(), x.end(), y.begin(), y.end(), v.begin());
87
0
    }
88
89
    template<class xIterator, class yIterator, class vIterator> inline
90
    GeneralLinearLeastSquares::GeneralLinearLeastSquares(
91
                                            xIterator xBegin, xIterator xEnd,
92
                                            yIterator yBegin, yIterator yEnd,
93
                                            vIterator vBegin, vIterator vEnd)
94
    : a_(std::distance(vBegin, vEnd), 0.0),
95
      err_(a_.size(), 0.0),
96
      residuals_(std::distance(yBegin, yEnd)),
97
      standardErrors_(a_.size()) {
98
        calculate(xBegin, xEnd, yBegin, yEnd, vBegin);
99
    }
100
101
102
    template <class xIterator, class yIterator, class vIterator>
103
    void GeneralLinearLeastSquares::calculate(xIterator xBegin, xIterator xEnd,
104
                                              yIterator yBegin, yIterator yEnd,
105
0
                                              vIterator vBegin) {
106
107
0
        const Size n = residuals_.size();
108
0
        const Size m = err_.size();
109
110
0
        QL_REQUIRE( n == Size(std::distance(yBegin, yEnd)),
111
0
            "sample set need to be of the same size");
112
0
        QL_REQUIRE(n >= m, "sample set is too small");
113
114
0
        Size i;
115
116
0
        Matrix A(n, m);
117
0
        for (i=0; i<m; ++i)
118
0
            std::transform(xBegin, xEnd, A.column_begin(i), *vBegin++);
119
120
0
        const SVD svd(A);
121
0
        const Matrix& V = svd.V();
122
0
        const Matrix& U = svd.U();
123
0
        const Array& w = svd.singularValues();
124
0
        const Real threshold = n * QL_EPSILON * svd.singularValues()[0];
125
126
0
        for (i=0; i<m; ++i) {
127
0
            if (w[i] > threshold) {
128
0
                const Real u = std::inner_product(U.column_begin(i),
129
0
                    U.column_end(i),
130
0
                    yBegin, Real(0.0))/w[i];
131
132
0
                for (Size j=0; j<m; ++j) {
133
0
                    a_[j]  +=u*V[j][i];
134
0
                    err_[j]+=V[j][i]*V[j][i]/(w[i]*w[i]);
135
0
                }
136
0
            }
137
0
        }
138
0
        err_      = Sqrt(err_);
139
0
        Array tmp = A*a_;
140
0
        std::transform(tmp.begin(), tmp.end(), yBegin, residuals_.begin(), std::minus<>());
141
142
0
        const Real chiSq
143
0
            = std::inner_product(residuals_.begin(), residuals_.end(), residuals_.begin(), Real(0.0));
144
0
        const Real multiplier = std::sqrt(chiSq/(n-2));
145
0
        std::transform(err_.begin(), err_.end(), standardErrors_.begin(),
146
0
                       [=](Real x) -> Real { return x * multiplier; });
147
0
    }
148
149
}
150
151
#endif