codac 1.5.6
Loading...
Searching...
No Matches
codac2_AnalyticFunction.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#include <map>
13#include "codac2_AnalyticExpr.h"
14#include "codac2_Domain.h"
16#include "codac2_FunctionBase.h"
20#include "codac2_operators.h"
21#include "codac2_cart_prod.h"
22
23namespace codac2
24{
25 enum class EvalMode
26 {
27 NATURAL = 0x01,
28 CENTERED = 0x02,
29 DEFAULT = 0x03 // corresponds to (NATURAL|CENTERED)
30 };
31
32 inline EvalMode operator&(EvalMode a, EvalMode b)
33 { return static_cast<EvalMode>(static_cast<int>(a) & static_cast<int>(b)); }
34
35 inline EvalMode operator|(EvalMode a, EvalMode b)
36 { return static_cast<EvalMode>(static_cast<int>(a) | static_cast<int>(b)); }
37
38 template<typename T>
39 requires std::is_base_of_v<AnalyticTypeBase,T>
40 class AnalyticFunction : public FunctionBase<AnalyticExpr<T>>
41 {
42 public:
43
44 AnalyticFunction(const FunctionArgsList& args, const ScalarExprList& y)
45 requires(std::is_same_v<T,VectorType>)
46 : FunctionBase<AnalyticExpr<T>>(args, y)
47 {
48 assert_release(y->belongs_to_args_list(this->args()) &&
49 "Invalid argument: variable not present in input arguments");
50 }
51
52 AnalyticFunction(const FunctionArgsList& args, const AnalyticExprWrapper<T>& y)
53 : FunctionBase<AnalyticExpr<T>>(args, y)
54 {
55 assert_release(y->belongs_to_args_list(this->args()) &&
56 "Invalid argument: variable not present in input arguments");
57 }
58
59 AnalyticFunction(const FunctionArgsList& args, const AnalyticVarExpr<T>& y)
60 : AnalyticFunction(args, { std::dynamic_pointer_cast<AnalyticExpr<T>>(y.copy()) })
61 { }
62
63 AnalyticFunction(const AnalyticFunction<T>& f)
64 : FunctionBase<AnalyticExpr<T>>(f)
65 { }
66
67 template<typename... X>
68 AnalyticExprWrapper<T> operator()(const X&... x) const
69 {
70 return { this->FunctionBase<AnalyticExpr<T>>::operator()(x...) };
71 }
72
73 template<typename... Args>
74 auto real_eval(const Args&... x) const
75 {
76 return eval(x...).mid();
77 }
78
79 template<typename... Args>
80 typename T::Domain eval(const EvalMode& m, const Args&... x) const
81 {
82 check_valid_inputs(x...);
83
84 switch(m)
85 {
86 case EvalMode::NATURAL:
87 {
88 return eval_<true>(x...).a;
89 }
90
91 case EvalMode::CENTERED:
92 {
93 auto x_ = eval_<false>(x...);
94 auto flatten_x = IntervalVector(cart_prod(x...));
95 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
96
97 if constexpr(std::is_same_v<T,ScalarType>)
98 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0];
99 else
100 return x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0);
101 }
102
103 case EvalMode::DEFAULT:
104 default:
105 {
106 auto x_ = eval_<false>(x...);
107
108 // If the centered form is not available for this expression...
109 if(x_.da.size() == 0 // .. because some parts have not yet been implemented,
110 || !x_.def_domain) // .. or due to restrictions in the derivative definition domain
111 return eval(EvalMode::NATURAL, x...);
112
113 else
114 {
115 auto flatten_x = IntervalVector(cart_prod(x...));
116 if constexpr(std::is_same_v<T,ScalarType>)
117 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0]);
118 else
119 {
120 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
121 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0));
122 }
123 }
124 }
125 }
126 }
127
128 template<typename... Args>
129 typename T::Domain eval(const Args&... x) const
130 {
131 return eval(EvalMode::NATURAL | EvalMode::CENTERED, x...);
132 }
133
134 template<typename... Args>
135 auto diff(const Args&... x) const
136 {
137 check_valid_inputs(x...);
138 return eval_<false>(x...).da;
139 }
140
141 Index output_size() const
142 {
143 if constexpr(std::is_same_v<T,ScalarType>)
144 return 1;
145
146 else if constexpr(std::is_same_v<T,VectorType>)
147 {
148 assert_release(this->args().size() == 1 && "unable (yet) to compute output size for multi-arg functions");
149
150 // A dump evaluation is performed to estimate the dimension
151 // of the image of this function. A natural evaluation is assumed
152 // to be faster.
153
154 if(dynamic_cast<ScalarVar*>(this->args()[0].get())) // if the argument is scalar
155 return eval(EvalMode::NATURAL, Interval()).size();
156 else
157 return eval(EvalMode::NATURAL, IntervalVector(this->input_size())).size();
158 }
159
160 else
161 {
162 assert_release(false && "unable to estimate output size");
163 return 0;
164 }
165 }
166
167 friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction<T>& f)
168 {
169 if constexpr(std::is_same_v<T,ScalarType>)
170 os << "scalar function";
171 else if constexpr(std::is_same_v<T,VectorType>)
172 os << "vector function";
173 return os;
174 }
175
176 protected:
177
178 template<typename Y>
179 friend class CtcInverse_;
180
181 template<typename D>
182 void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const
183 {
184 assert(i >= 0 && i < (Index)this->args().size());
185 assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs");
186
187 using D_TYPE = typename ValueType<D>::Type;
188
189 IntervalMatrix d(0,0); // derivatives disabled for matrix inputs
190
191 if constexpr(!std::is_same_v<D_TYPE,MatrixType>)
192 {
193 d = IntervalMatrix::zero(size_of(x), this->args().total_size());
194
195 Index p = 0;
196 for(Index j = 0 ; j < i ; j++)
197 p += this->args()[j]->size();
198
199 for(Index k = p ; k < p+size_of(x) ; k++)
200 d(k-p,k) = 1.;
201 }
202
203 v[this->args()[i]->unique_id()] =
204 std::make_shared<D_TYPE>(typename D_TYPE::Domain(x).mid(), x, d, true);
205 }
206
207 template<typename... Args>
208 void fill_from_args(ValuesMap& v, const Args&... x) const
209 {
210 Index i = 0;
211 (add_value_to_arg_map(v, x, i++), ...);
212 }
213
214 template<typename D>
215 void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const
216 {
217 assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found");
218 x &= std::dynamic_pointer_cast<typename ValueType<D>::Type>(v.at(this->args()[i]->unique_id()))->a;
219 }
220
221 template<typename... Args>
222 void intersect_from_args(const ValuesMap& v, Args&... x) const
223 {
224 Index i = 0;
225 (intersect_value_from_arg_map(v, x, i++), ...);
226 }
227
228 template<bool NATURAL_EVAL,typename... Args>
229 auto eval_(const Args&... x) const
230 {
231 ValuesMap v;
232
233 if constexpr(sizeof...(Args) == 0)
234 return this->expr()->fwd_eval(v, 0, NATURAL_EVAL);
235
236 else
237 {
238 fill_from_args(v, x...);
239 return this->expr()->fwd_eval(v, cart_prod(x...).size(), NATURAL_EVAL); // todo: improve size computation
240 }
241 }
242
243 template<typename... Args>
244 void check_valid_inputs(const Args&... x) const
245 {
246 [[maybe_unused]] Index n = 0;
247 ((n += size_of(x)), ...);
248
249 assert_release(this->_args.total_size() == n &&
250 "Invalid arguments: wrong number of input arguments");
251 }
252 };
253
254 AnalyticFunction(const FunctionArgsList&, double) ->
255 AnalyticFunction<ScalarType>;
256
257 AnalyticFunction(const FunctionArgsList&, const Interval&) ->
258 AnalyticFunction<ScalarType>;
259
260 AnalyticFunction(const FunctionArgsList&, std::initializer_list<int>) ->
261 AnalyticFunction<VectorType>;
262
263 AnalyticFunction(const FunctionArgsList&, std::initializer_list<double>) ->
264 AnalyticFunction<VectorType>;
265
266 AnalyticFunction(const FunctionArgsList&, std::initializer_list<Interval>) ->
267 AnalyticFunction<VectorType>;
268
269 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarExpr>) ->
270 AnalyticFunction<VectorType>;
271
272 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarVar>) ->
273 AnalyticFunction<VectorType>;
274
275 template<typename T>
276 AnalyticFunction(const FunctionArgsList&, const T&) ->
277 AnalyticFunction<typename ValueType<T>::Type>;
278
279}
Interval class, for representing closed and connected subsets of .
Definition codac2_Interval.h:62