64 {
65
67 "protection end (" << protectionEnd <<
") must be > reference date (" <<
referenceDate <<
")");
68
69
70
71 std::vector<Date> accrualDates;
72 for (auto const& l : underlying) {
73 for (auto const& c : l) {
74 if (auto f = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(c)) {
75 accrualDates.push_back(f->accrualEndDate());
76 }
77 }
78 }
79
80
81
82 accrualDates.push_back(std::max(protectionStart,
referenceDate));
83 accrualDates.push_back(protectionEnd);
84
85 std::sort(accrualDates.begin(), accrualDates.end());
86 auto it = std::unique(accrualDates.begin(), accrualDates.end());
87 accrualDates.resize(it - accrualDates.begin());
88
89 auto itStart = std::lower_bound(accrualDates.begin(), accrualDates.end(),
referenceDate);
90 auto itEnd = std::upper_bound(accrualDates.begin(), accrualDates.end(), protectionEnd);
91
92 QL_REQUIRE(std::distance(itStart, itEnd) >= 2, "got invalid discretisationGrid for RPA, this is unexpected");
93
94 std::vector<Date> gridDates(itStart, itEnd);
95
96
97
98 if (maxGapDays != Null<Size>()) {
99 bool refining;
100
101 Size refiningIterations = 0;
102 do {
103 refining = false;
104 for (auto it = gridDates.begin(); it < gridDates.end() - 1; ++it) {
105 if (*(it + 1) - *it > std::max<int>(1, maxGapDays)) {
106 it = gridDates.insert(it + 1, *it + (*(it + 1) - *it) / 2);
107 refining = true;
108 }
109 }
110 } while (refining && ++refiningIterations < 100);
111 QL_REQUIRE(refiningIterations < 100, "discretisationGrid refinement failed, this is unexpected");
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 Size currentNumberOfDiscretisationPoints = gridDates.size() - 1,
128 previousNumberOfDiscretisationPoints = QL_MAX_INTEGER;
129
130 while (maxDiscretisationPoints != Null<Size>() && currentNumberOfDiscretisationPoints > maxDiscretisationPoints &&
131 currentNumberOfDiscretisationPoints < previousNumberOfDiscretisationPoints) {
132
133 previousNumberOfDiscretisationPoints = currentNumberOfDiscretisationPoints;
134 Size currentLeftIndex = 0, currentRightIndex = gridDates.size() - 1;
135 bool nextErasureOnLeft = true, canRemoveFurtherPointsInPass = true;
136
137 while (currentNumberOfDiscretisationPoints > maxDiscretisationPoints && canRemoveFurtherPointsInPass) {
138 if (nextErasureOnLeft) {
139 if (gridDates.size() >= currentLeftIndex + 4 && currentLeftIndex + 3 <= currentRightIndex) {
140 gridDates.erase(std::next(gridDates.begin(), currentLeftIndex + 1),
141 std::next(gridDates.begin(), currentLeftIndex + 3));
142 currentNumberOfDiscretisationPoints -= 2;
143 currentRightIndex -= 2;
144 currentLeftIndex++;
145 nextErasureOnLeft = false;
146 } else {
147 canRemoveFurtherPointsInPass = false;
148 }
149 } else {
150 if (currentRightIndex >= 3 && currentLeftIndex + 3 <= currentRightIndex) {
151 gridDates.erase(std::next(gridDates.begin(), currentRightIndex - 2),
152 std::next(gridDates.begin(), currentRightIndex));
153 currentNumberOfDiscretisationPoints -= 2;
154 currentRightIndex -= 3;
155 nextErasureOnLeft = true;
156 } else {
157 canRemoveFurtherPointsInPass = false;
158 }
159 }
160
161
162 }
163 }
164
165 return gridDates;
166}