codac 2.0.0
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"
19#include "codac2_operators.h"
20#include "codac2_cart_prod.h"
21#include "codac2_vec.h"
22#include "codac2_Wrapper.h"
24#include "codac2_peibos_tools.h"
25
26namespace codac2
27{
28 enum class EvalMode
29 {
30 NATURAL = 0x01,
31 CENTERED = 0x02,
32 DEFAULT = 0x03 // corresponds to (NATURAL|CENTERED)
33 };
34
35 inline EvalMode operator&(EvalMode a, EvalMode b)
36 { return static_cast<EvalMode>(static_cast<int>(a) & static_cast<int>(b)); }
37
38 inline EvalMode operator|(EvalMode a, EvalMode b)
39 { return static_cast<EvalMode>(static_cast<int>(a) | static_cast<int>(b)); }
40
41 struct ScalarExprList : public AnalyticExprWrapper<VectorType>
42 {
43 // Mainly used to take advantage of initializer lists in AnalyticFunction constructors.
44 template<typename... S>
45 requires (std::is_same_v<typename ExprType<S>::Type,ScalarType> && ...)
46 ScalarExprList(const S&... y)
47 : AnalyticExprWrapper<VectorType>(vec(y...))
48 { }
49 };
50
51 template<typename T>
52 class SampledTraj;
53
54 template<typename T>
55 class SlicedTube;
56
57 template<typename T>
58 requires std::is_base_of_v<AnalyticTypeBase,T>
59 class AnalyticFunction : public FunctionBase<AnalyticExpr<T>>
60 {
61 public:
62
63 AnalyticFunction(const FunctionArgsList& args, const ScalarExprList& y)
64 requires(std::is_same_v<T,VectorType>)
65 : FunctionBase<AnalyticExpr<T>>(args, y)
66 {
67 assert_release(y->belongs_to_args_list(this->args()) &&
68 "Invalid argument: variable not present in input arguments");
69 update_var_names();
70 }
71
72 AnalyticFunction(const FunctionArgsList& args, const AnalyticExprWrapper<T>& y)
73 : FunctionBase<AnalyticExpr<T>>(args, y)
74 {
75 assert_release(y->belongs_to_args_list(this->args()) &&
76 "Invalid argument: variable not present in input arguments");
77 update_var_names();
78 }
79
80 AnalyticFunction(const AnalyticFunction<T>& f)
81 : FunctionBase<AnalyticExpr<T>>(f)
82 { }
83
84 template<typename... X>
85 AnalyticExprWrapper<T> operator()(const X&... x) const
86 {
87 return { this->FunctionBase<AnalyticExpr<T>>::operator()(x...) };
88 }
89
90 template<typename... Args>
91 auto real_eval(const Args&... x) const
92 {
93 return eval(x...).mid();
94 }
95
96 template<typename... Args>
97 typename T::Domain eval(const EvalMode& m, const Args&... x) const
98 {
99 check_valid_inputs(x...);
100
101 switch(m)
102 {
103 case EvalMode::NATURAL:
104 {
105 return eval_<true>(x...).a;
106 }
107
108 case EvalMode::CENTERED:
109 {
110 auto x_ = eval_<false>(x...);
111 auto flatten_x = IntervalVector(cart_prod(x...));
112 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
113
114 if constexpr(std::is_same_v<T,ScalarType>)
115 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0];
116
117 else if constexpr(std::is_same_v<T,VectorType>)
118 return x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0);
119
120 else
121 {
122 static_assert(std::is_same_v<T,MatrixType>);
123 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))
124 .reshaped(x_.m.rows(), x_.m.cols());
125 }
126 }
127
128 case EvalMode::DEFAULT:
129 default:
130 {
131 auto x_ = eval_<false>(x...);
132
133 // If the centered form is not available for this expression...
134 if(x_.da.size() == 0 // .. because some parts have not yet been implemented,
135 || !x_.def_domain) // .. or due to restrictions in the derivative definition domain
136 return x_.a; // natural evaluation
137
138 else
139 {
140 auto flatten_x = IntervalVector(cart_prod(x...));
141
142 if constexpr(std::is_same_v<T,ScalarType>)
143 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0]);
144
145 else if constexpr(std::is_same_v<T,VectorType>)
146 {
147 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
148 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0));
149 }
150
151 else
152 {
153 static_assert(std::is_same_v<T,MatrixType>);
154 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
155 return x_.a & (x_.m +(x_.da*(flatten_x-flatten_x.mid()))
156 .reshaped(x_.m.rows(),x_.m.cols()));
157 }
158 }
159 }
160 }
161 }
162
163 template<typename... X>
164 typename T::Domain eval_default_codomain() const
165 {
166 static_assert(sizeof...(X) > 0);
167 assert_release(this->args().size() == sizeof...(X)
168 && "eval_default_codomain: function arity does not match contractor signature");
169
170 return eval_default_codomain_impl<X...>(
171 std::index_sequence_for<X...>{}
172 );
173 }
174
175 template<typename... Args>
176 auto diff(const Args&... x) const
177 {
178 check_valid_inputs(x...);
179 return eval_<false>(x...).da;
180 }
181
182 template<typename... Args>
183 typename T::Domain eval(const Args&... x) const
184 {
185 return eval(EvalMode::NATURAL | EvalMode::CENTERED, x...);
186 }
187
188 template<typename... Args>
189 auto traj_eval(const SampledTraj<Args>&... x) const
190 {
191 SampledTraj<typename T::Scalar> y;
192 for(const auto& [ti,xi] : std::get<0>(std::tie(x...)))
193 y.set(this->real_eval(x(ti)...),ti);
194 return y;
195 }
196
197 template<typename... Args>
198 auto tube_eval(const SlicedTube<Args>&... x) const
199 {
200 auto tdomain = std::get<0>(std::tie(x...)).tdomain();
201
202 SlicedTube<typename T::Domain> y(
203 tdomain, (typename T::Domain)(this->output_size())
204 );
205
206 for(auto it = tdomain->begin() ; it != tdomain->end() ; it++)
207 y.slice(it)->codomain() = this->eval(x.slice(it)->codomain()...);
208
209 return y;
210 }
211
212 template<typename... Args>
213 requires std::is_same_v<VectorType,T> && ((!std::is_same_v<MatrixType,typename ExprType<Args>::Type>) && ...)
214 Parallelepiped parallelepiped_eval(const Args&... x) const
215 {
216 this->check_valid_inputs(x...);
217 assert_release(this->input_size() < this->output_size() &&
218 "Parallelepiped evaluation requires more outputs than inputs.");
219 assert_release(this->input_size() > 0 &&
220 "Parallelepiped evaluation requires at least one input.");
221
222 IntervalVector Y = this->eval(((typename Wrapper<Args>::Domain)(x)).mid()...);
223 Vector z = Y.mid();
224
225 Matrix A = this->diff(((typename Wrapper<Args>::Domain)(x)).mid()...).mid();
226
227 // Maximum error computation
228 double rho = error_peibos(Y, z, this->diff(x...), A, cart_prod(x...));
229
230 // Inflation of the parallelepiped
231 Matrix A_inf = inflate_flat_parallelepiped(A, (cart_prod(x...).template cast<Interval>()).rad(), rho);
232
233 return Parallelepiped(z, A_inf);
234 }
235
236 Index output_size() const
237 {
238 if constexpr(std::is_same_v<T,ScalarType>)
239 return 1;
240
241 else {
242 std::pair<Index,Index> oshape = output_shape();
243 return oshape.first * oshape.second;
244 }
245 }
246
247 std::pair<Index,Index> output_shape() const
248 {
249 if constexpr(std::is_same_v<T,ScalarType>)
250 return {1,1};
251 else return this->expr()->output_shape();
252 }
253
254 friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction<T>& f)
255 {
256 os << "(";
257 for(size_t i = 0 ; i < f.args().size() ; i++)
258 os << (i!=0 ? "," : "") << f.args()[i]->name();
259 os << ") ↦ " << f.expr()->str();
260 return os;
261 }
262
263 // not working with Clang: template<typename Y, typename... X>
264 // not working with Clang: requires (sizeof...(X) > 0)
265 // not working with Clang: friend class CtcInverse;
266
267 // So, the following methods are temporarily public
268
269 // protected:
270
271 template<typename... Args>
272 void fill_from_args(ValuesMap& v, const Args&... x) const
273 {
274 Index i = 0;
275 (add_value_to_arg_map(v, x, i++), ...);
276 }
277
278 template<typename... Args>
279 void intersect_from_args(const ValuesMap& v, Args&... x) const
280 {
281 Index i = 0;
282 (intersect_value_from_arg_map(v, x, i++), ...);
283 }
284
285 protected:
286
287 template<typename D>
288 void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const
289 {
290 assert(i >= 0 && i < (Index)this->args().size());
291 assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs");
292
293 using D_TYPE = typename ExprType<D>::Type;
294
295 IntervalMatrix d = IntervalMatrix::zero(size_of(x), this->args().total_size());
296
297 Index p = 0;
298 for(Index j = 0 ; j < i ; j++)
299 p += this->args()[j]->size();
300
301 for(Index k = p ; k < p+size_of(x) ; k++)
302 d(k-p,k) = 1.;
303
304 v[this->args()[i]->unique_id()] =
305 std::make_shared<D_TYPE>(typename D_TYPE::Domain(x).mid(), x, d, true);
306 }
307
308 template<typename D>
309 void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const
310 {
311 assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found");
312 x &= std::dynamic_pointer_cast<typename ExprType<D>::Type>(v.at(this->args()[i]->unique_id()))->a;
313 }
314
315 template<bool NATURAL_EVAL,typename... Args>
316 auto eval_(const Args&... x) const
317 {
318 ValuesMap v;
319
320 if constexpr(sizeof...(Args) == 0)
321 return this->expr()->fwd_eval(v, 0, NATURAL_EVAL);
322
323 else
324 {
325 fill_from_args(v, x...);
326 return this->expr()->fwd_eval(v, this->input_size(), NATURAL_EVAL);
327 }
328 }
329
330 template<typename... Args>
331 void check_valid_inputs(const Args&... x) const
332 {
333 [[maybe_unused]] Index n = 0;
334 ((n += size_of(x)), ...);
335
336 assert_release(this->_args.total_size() == n &&
337 "Invalid arguments: wrong number of input arguments");
338 }
339
340 inline void update_var_names()
341 {
342 for(const auto& v : this->_args) // variable names are automatically computed in FunctionArgsList,
343 // so we propagate them to the expression
344 this->_y->replace_arg(v->unique_id(), std::dynamic_pointer_cast<ExprBase>(v));
345 }
346
347 template<typename X>
348 static X default_eval_input(const std::shared_ptr<VarBase>& arg)
349 {
350 if constexpr(std::is_same_v<X,Interval>)
351 return Interval();
352 else if constexpr(std::is_same_v<X,IntervalVector>)
353 return IntervalVector(arg->size());
354 else
355 {
356 static_assert(!std::is_same_v<X,X>,
357 "default_eval_input: unsupported input type");
358 }
359 }
360
361 template<typename... X, std::size_t... I>
362 typename T::Domain eval_default_codomain_impl(std::index_sequence<I...>) const
363 {
364 return this->eval(default_eval_input<X>(this->args()[I])...);
365 }
366 };
367
368 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarExpr>) ->
369 AnalyticFunction<VectorType>;
370
371 template<typename T>
372 AnalyticFunction(const FunctionArgsList&, const T&) ->
373 AnalyticFunction<typename ExprType<T>::Type>;
374
375}
A container class to manage a collection of function arguments.
Definition codac2_FunctionArgsList.h:25
A base class for functions (either analytic functions, or set functions).
Definition codac2_FunctionBase.h:41
const FunctionArgsList & args() const
Definition codac2_FunctionBase.h:93
const FunctionArgsList _args
Definition codac2_FunctionBase.h:218
FunctionBase(const std::vector< std::reference_wrapper< VarBase > > &args, const std::shared_ptr< AnalyticExpr< T > > &y)
Definition codac2_FunctionBase.h:52
Index input_size() const
Definition codac2_FunctionBase.h:165
const std::shared_ptr< AnalyticExpr< T > > _y
Definition codac2_FunctionBase.h:217
const std::shared_ptr< AnalyticExpr< T > > & expr() const
Definition codac2_FunctionBase.h:113
auto mid() const
Returns a matrix containing the midpoints of each interval element.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:117
Definition codac2_OctaSym.h:21
Eigen::Matrix< double,-1, 1 > Vector
Alias for a dynamically-sized column vector of doubles.
Definition codac2_Vector.h:24
Matrix inflate_flat_parallelepiped(const Matrix &A, const Vector &e_vec, double rho)
Inflate the flat parallelepiped by .
double error_peibos(const IntervalVector &Y, const Vector &z, const IntervalMatrix &Jf, const Matrix &A, const IntervalVector &X)
Compute the error term for the parallelepiped inclusion. The error is later used to inflate the flat ...
Eigen::Matrix< Interval,-1, 1 > IntervalVector
Alias for a dynamic-size column vector of intervals.
Definition codac2_IntervalVector.h:25
CtcInterType< typenameC1::ContractedTypes >::Ctc operator&(const C1 &c1, const C2 &c2)
Builds an intersection contractor from two contractors.
Definition codac2_CtcInter.h:200
Eigen::Matrix< double,-1,-1 > Matrix
Alias for a dynamic-size matrix of doubles.
Definition codac2_Matrix.h:26
Eigen::Matrix< Interval,-1,-1 > IntervalMatrix
Alias for a dynamic-size matrix of intervals.
Definition codac2_IntervalMatrix.h:25