/src/quantlib/ql/math/optimization/constraint.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) 2001, 2002, 2003 Sadruddin Rejeb |
5 | | Copyright (C) 2012 Mateusz Kapturski |
6 | | |
7 | | This file is part of QuantLib, a free-software/open-source library |
8 | | for financial quantitative analysts and developers - http://quantlib.org/ |
9 | | |
10 | | QuantLib is free software: you can redistribute it and/or modify it |
11 | | under the terms of the QuantLib license. You should have received a |
12 | | copy of the license along with this program; if not, please email |
13 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
14 | | <https://www.quantlib.org/license.shtml>. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, but WITHOUT |
17 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
18 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
19 | | */ |
20 | | |
21 | | /*! \file constraint.hpp |
22 | | \brief Abstract constraint class |
23 | | */ |
24 | | |
25 | | #ifndef quantlib_optimization_constraint_h |
26 | | #define quantlib_optimization_constraint_h |
27 | | |
28 | | #include <ql/math/array.hpp> |
29 | | #include <algorithm> |
30 | | #include <utility> |
31 | | |
32 | | namespace QuantLib { |
33 | | |
34 | | //! Base constraint class |
35 | | class Constraint { |
36 | | protected: |
37 | | //! Base class for constraint implementations |
38 | | class Impl { |
39 | | public: |
40 | 0 | virtual ~Impl() = default; |
41 | | //! Tests if params satisfy the constraint |
42 | | virtual bool test(const Array& params) const = 0; |
43 | | //! Returns upper bound for given parameters |
44 | 0 | virtual Array upperBound(const Array& params) const { |
45 | 0 | return Array(params.size(), |
46 | 0 | std::numeric_limits < Array::value_type > ::max()); |
47 | 0 | } |
48 | | //! Returns lower bound for given parameters |
49 | 0 | virtual Array lowerBound(const Array& params) const { |
50 | 0 | return Array(params.size(), |
51 | 0 | -std::numeric_limits < Array::value_type > ::max()); |
52 | 0 | } |
53 | | }; |
54 | | ext::shared_ptr<Impl> impl_; |
55 | | public: |
56 | 0 | bool empty() const { return !impl_; } |
57 | 0 | bool test(const Array& p) const { return impl_->test(p); } |
58 | 0 | Array upperBound(const Array& params) const { |
59 | 0 | Array result = impl_->upperBound(params); |
60 | 0 | QL_REQUIRE(params.size() == result.size(), |
61 | 0 | "upper bound size (" << result.size() |
62 | 0 | << ") not equal to params size (" |
63 | 0 | << params.size() << ")"); |
64 | 0 | return result; |
65 | 0 | } |
66 | 0 | Array lowerBound(const Array& params) const { |
67 | 0 | Array result = impl_->lowerBound(params); |
68 | 0 | QL_REQUIRE(params.size() == result.size(), |
69 | 0 | "lower bound size (" << result.size() |
70 | 0 | << ") not equal to params size (" |
71 | 0 | << params.size() << ")"); |
72 | 0 | return result; |
73 | 0 | } |
74 | | Real update(Array& p, const Array& direction, Real beta) const; |
75 | | Constraint(ext::shared_ptr<Impl> impl = ext::shared_ptr<Impl>()); |
76 | | }; |
77 | | |
78 | | //! No constraint |
79 | | class NoConstraint : public Constraint { |
80 | | private: |
81 | | class Impl final : public Constraint::Impl { |
82 | | public: |
83 | 0 | bool test(const Array&) const override { return true; } |
84 | | }; |
85 | | public: |
86 | | NoConstraint() |
87 | 0 | : Constraint(ext::shared_ptr<Constraint::Impl>( |
88 | 0 | new NoConstraint::Impl)) {} |
89 | | }; |
90 | | |
91 | | //! %Constraint imposing positivity to all arguments |
92 | | class PositiveConstraint : public Constraint { |
93 | | private: |
94 | | class Impl final : public Constraint::Impl { |
95 | | public: |
96 | 0 | bool test(const Array& params) const override { |
97 | 0 | return std::all_of(params.begin(), params.end(), [](Real p) { return p > 0.0; }); |
98 | 0 | } |
99 | 0 | Array upperBound(const Array& params) const override { |
100 | 0 | return Array(params.size(), |
101 | 0 | std::numeric_limits < Array::value_type > ::max()); |
102 | 0 | } |
103 | 0 | Array lowerBound(const Array& params) const override { |
104 | 0 | return Array(params.size(), 0.0); |
105 | 0 | } |
106 | | }; |
107 | | public: |
108 | | PositiveConstraint() |
109 | 0 | : Constraint(ext::shared_ptr<Constraint::Impl>( |
110 | 0 | new PositiveConstraint::Impl)) {} |
111 | | }; |
112 | | |
113 | | //! %Constraint imposing all arguments to be in [low,high] |
114 | | class BoundaryConstraint : public Constraint { |
115 | | private: |
116 | | class Impl final : public Constraint::Impl { |
117 | | public: |
118 | | Impl(Real low, Real high) |
119 | 0 | : low_(low), high_(high) {} |
120 | 0 | bool test(const Array& params) const override { |
121 | 0 | return std::all_of(params.begin(), params.end(), [this](Real p) { return low_ <= p && p <= high_; }); |
122 | 0 | } |
123 | 0 | Array upperBound(const Array& params) const override { |
124 | 0 | return Array(params.size(), high_); |
125 | 0 | } |
126 | 0 | Array lowerBound(const Array& params) const override { |
127 | 0 | return Array(params.size(), low_); |
128 | 0 | } |
129 | | |
130 | | private: |
131 | | Real low_, high_; |
132 | | }; |
133 | | public: |
134 | | BoundaryConstraint(Real low, Real high) |
135 | 0 | : Constraint(ext::shared_ptr<Constraint::Impl>( |
136 | 0 | new BoundaryConstraint::Impl(low, high))) {} |
137 | | }; |
138 | | |
139 | | //! %Constraint enforcing both given sub-constraints |
140 | | class CompositeConstraint : public Constraint { |
141 | | private: |
142 | | class Impl final : public Constraint::Impl { |
143 | | public: |
144 | 0 | Impl(Constraint c1, Constraint c2) : c1_(std::move(c1)), c2_(std::move(c2)) {} |
145 | 0 | bool test(const Array& params) const override { |
146 | 0 | return c1_.test(params) && c2_.test(params); |
147 | 0 | } |
148 | 0 | Array upperBound(const Array& params) const override { |
149 | 0 | Array c1ub = c1_.upperBound(params); |
150 | 0 | Array c2ub = c2_.upperBound(params); |
151 | 0 | Array rtrnArray(c1ub.size(), 0.0); |
152 | 0 | for (Size iter = 0; iter < c1ub.size(); iter++) { |
153 | 0 | rtrnArray.at(iter) = std::min(c1ub.at(iter), c2ub.at(iter)); |
154 | 0 | } |
155 | 0 | return rtrnArray; |
156 | 0 | } |
157 | 0 | Array lowerBound(const Array& params) const override { |
158 | 0 | Array c1lb = c1_.lowerBound(params); |
159 | 0 | Array c2lb = c2_.lowerBound(params); |
160 | 0 | Array rtrnArray(c1lb.size(), 0.0); |
161 | 0 | for (Size iter = 0; iter < c1lb.size(); iter++) { |
162 | 0 | rtrnArray.at(iter) = std::max(c1lb.at(iter), c2lb.at(iter)); |
163 | 0 | } |
164 | 0 | return rtrnArray; |
165 | 0 | } |
166 | | |
167 | | private: |
168 | | Constraint c1_, c2_; |
169 | | }; |
170 | | public: |
171 | | CompositeConstraint(const Constraint& c1, const Constraint& c2) |
172 | 0 | : Constraint(ext::shared_ptr<Constraint::Impl>( |
173 | 0 | new CompositeConstraint::Impl(c1,c2))) {} |
174 | | }; |
175 | | |
176 | | //! %Constraint imposing i-th argument to be in [low_i,high_i] for all i |
177 | | class NonhomogeneousBoundaryConstraint: public Constraint { |
178 | | private: |
179 | | class Impl final : public Constraint::Impl { |
180 | | public: |
181 | 0 | Impl(Array low, Array high) : low_(std::move(low)), high_(std::move(high)) { |
182 | 0 | QL_ENSURE(low_.size()==high_.size(), |
183 | 0 | "Upper and lower boundaries sizes are inconsistent."); |
184 | 0 | } |
185 | 0 | bool test(const Array& params) const override { |
186 | 0 | QL_ENSURE(params.size()==low_.size(), |
187 | 0 | "Number of parameters and boundaries sizes are inconsistent."); |
188 | 0 | for (Size i = 0; i < params.size(); i++) { |
189 | 0 | if ((params[i] < low_[i]) || (params[i] > high_[i])) |
190 | 0 | return false; |
191 | 0 | } |
192 | 0 | return true; |
193 | 0 | } |
194 | 0 | Array upperBound(const Array&) const override { return high_; } |
195 | 0 | Array lowerBound(const Array&) const override { return low_; } |
196 | | |
197 | | private: |
198 | | Array low_, high_; |
199 | | }; |
200 | | public: |
201 | | NonhomogeneousBoundaryConstraint(const Array& low, const Array& high) |
202 | | : Constraint(ext::shared_ptr<Constraint::Impl>( |
203 | 0 | new NonhomogeneousBoundaryConstraint::Impl(low, high))) {} |
204 | | }; |
205 | | |
206 | | } |
207 | | |
208 | | #endif |