/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 | | } |