Coverage Report

Created: 2026-03-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/matrixutilities/basisincompleteordered.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
Copyright (C) 2007, 2008 Mark Joshi
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
<https://www.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
#include <ql/math/matrixutilities/basisincompleteordered.hpp>
21
#include <algorithm>
22
23
namespace QuantLib {
24
25
    BasisIncompleteOrdered::BasisIncompleteOrdered(Size euclideanDimension)
26
0
        : euclideanDimension_(euclideanDimension) {}
27
28
0
    bool BasisIncompleteOrdered::addVector(const Array& newVector1) {
29
30
0
        QL_REQUIRE(newVector1.size() == euclideanDimension_,
31
0
            "missized vector passed to "
32
0
            "BasisIncompleteOrdered::addVector");
33
34
0
        newVector_ = newVector1;
35
36
0
        if (currentBasis_.size()==euclideanDimension_)
37
0
            return false;
38
39
0
        for (auto& currentBasi : currentBasis_) {
40
0
            Real innerProd =
41
0
                std::inner_product(newVector_.begin(), newVector_.end(), currentBasi.begin(), Real(0.0));
42
43
0
            for (Size k=0; k<euclideanDimension_; ++k)
44
0
                newVector_[k] -= innerProd * currentBasi[k];
45
0
        }
46
47
0
        Real norm = std::sqrt(std::inner_product(newVector_.begin(),
48
0
            newVector_.end(),
49
0
            newVector_.begin(), Real(0.0)));
50
51
0
        if (norm<1e-12) // maybe this should be a tolerance
52
0
            return false;
53
54
0
        for (Size l=0; l<euclideanDimension_; ++l)
55
0
            newVector_[l]/=norm;
56
57
0
        currentBasis_.push_back(newVector_);
58
59
0
        return true;
60
0
    }
61
62
0
    Size BasisIncompleteOrdered::basisSize() const {
63
0
        return currentBasis_.size();
64
0
    }
65
66
0
    Size BasisIncompleteOrdered::euclideanDimension() const {
67
0
        return euclideanDimension_;
68
0
    }
69
70
71
0
    Matrix BasisIncompleteOrdered::getBasisAsRowsInMatrix() const {
72
0
        Matrix basis(currentBasis_.size(), euclideanDimension_);
73
0
        for (Size i=0; i<basis.rows(); ++i)
74
0
            for (Size j=0; j<basis.columns(); ++j)
75
0
                basis[i][j] = currentBasis_[i][j];
76
77
0
        return basis;
78
0
    }
79
80
    namespace
81
    {
82
        Real normSquared(const Matrix& v, Size row)
83
0
        {
84
0
            Real x=0.0;
85
0
            for (Size i=0; i < v.columns(); ++i)
86
0
                x += v[row][i]*v[row][i];
87
88
0
            return x;
89
0
        }
90
91
92
        Real norm(const Matrix& v, Size row)
93
0
        {
94
0
            return std::sqrt(normSquared( v,  row));
95
0
        }
96
97
        Real innerProduct(const Matrix& v, Size row1, const Matrix& w, Size row2)
98
0
        {
99
100
0
            Real x=0.0;
101
0
            for (Size i=0; i < v.columns(); ++i)
102
0
                x += v[row1][i]*w[row2][i];
103
104
0
            return x;
105
0
        }
106
107
    }
108
109
110
111
    OrthogonalProjections::OrthogonalProjections(const Matrix& originalVectors,
112
                                                 Real multiplierCutoff,
113
                                                 Real tolerance)
114
0
    : originalVectors_(originalVectors),
115
0
      multiplierCutoff_(multiplierCutoff),
116
0
      numberVectors_(originalVectors.rows()),
117
0
      dimension_(originalVectors.columns()),
118
0
      validVectors_(true,originalVectors.rows()), // opposite way round from vector constructor
119
0
      orthoNormalizedVectors_(originalVectors.rows(),
120
0
                              originalVectors.columns())
121
0
    {
122
0
        std::vector<Real> currentVector(dimension_);
123
0
        for (Size j=0; j < numberVectors_; ++j)
124
0
        {
125
126
0
            if (validVectors_[j])
127
0
            {
128
0
                for (Size k=0; k< numberVectors_; ++k) // create an orthormal basis not containing j
129
0
                {
130
0
                    for (Size m=0; m < dimension_; ++m)
131
0
                        orthoNormalizedVectors_[k][m] = originalVectors_[k][m];
132
133
0
                    if ( k !=j && validVectors_[k])
134
0
                    {
135
136
137
0
                        for (Size l=0; l < k; ++l)
138
0
                        {
139
0
                            if (validVectors_[l] && l !=j)
140
0
                            {
141
0
                                Real dotProduct = innerProduct(orthoNormalizedVectors_, k, orthoNormalizedVectors_,l);
142
0
                                for (Size n=0; n < dimension_; ++n)
143
0
                                    orthoNormalizedVectors_[k][n] -=  dotProduct*orthoNormalizedVectors_[l][n];
144
0
                            }
145
146
0
                        }
147
148
0
                        Real normBeforeScaling= norm(orthoNormalizedVectors_,k);
149
150
0
                        if (normBeforeScaling < tolerance)
151
0
                        {
152
0
                            validVectors_[k] = false;
153
0
                        }
154
0
                        else
155
0
                        {
156
0
                            Real normBeforeScalingRecip = 1.0/normBeforeScaling;
157
0
                            for (Size m=0; m < dimension_; ++m)
158
0
                                orthoNormalizedVectors_[k][m] *= normBeforeScalingRecip;
159
160
0
                        } // end of else (norm < tolerance)
161
162
0
                    } // end of if k !=j && validVectors_[k])
163
164
0
                }// end of  for (Size k=0; k< numberVectors_; ++k)
165
166
                // we now have an o.n. basis for everything except  j
167
168
0
                Real prevNormSquared = normSquared(originalVectors_, j);
169
170
171
0
                for (Size r=0; r < numberVectors_; ++r)
172
0
                    if (validVectors_[r] && r != j)
173
0
                    {
174
0
                        Real dotProduct = innerProduct(orthoNormalizedVectors_, j, orthoNormalizedVectors_,r);
175
176
0
                        for (Size s=0; s < dimension_; ++s)
177
0
                           orthoNormalizedVectors_[j][s] -= dotProduct*orthoNormalizedVectors_[r][s];
178
179
0
                    }
180
181
0
               Real projectionOnOriginalDirection = innerProduct(originalVectors_,j,orthoNormalizedVectors_,j);
182
0
               Real sizeMultiplier = prevNormSquared/projectionOnOriginalDirection;
183
184
0
               if (std::fabs(sizeMultiplier) < multiplierCutoff_)
185
0
               {
186
0
                    for (Size t=0; t < dimension_; ++t)
187
0
                        currentVector[t] = orthoNormalizedVectors_[j][t]*sizeMultiplier;
188
189
0
               }
190
0
               else
191
0
                   validVectors_[j] = false;
192
193
194
0
            } // end of  if (validVectors_[j])
195
196
0
            projectedVectors_.push_back(currentVector);
197
198
199
0
        } //end of j loop
200
201
0
        numberValidVectors_ =0;
202
0
        for (Size i=0; i < numberVectors_; ++i)
203
0
            numberValidVectors_ +=  validVectors_[i] ? 1 : 0;
204
205
206
0
    } // end of constructor
207
208
    const std::valarray<bool>& OrthogonalProjections::validVectors() const
209
0
    {
210
0
        return validVectors_;
211
212
0
    }
213
214
    const std::vector<Real>& OrthogonalProjections::GetVector(Size index) const
215
0
    {
216
0
        return projectedVectors_[index];
217
0
    }
218
219
220
  Size OrthogonalProjections::numberValidVectors() const
221
0
  {
222
0
        return numberValidVectors_;
223
0
  }
224
225
226
227
228
}