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 eval(EvalMode::NATURAL, x...);
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... Args>
164 auto diff(const Args&... x) const
165 {
166 check_valid_inputs(x...);
167 return eval_<false>(x...).da;
168 }
169
170 template<typename... Args>
171 typename T::Domain eval(const Args&... x) const
172 {
173 return eval(EvalMode::NATURAL | EvalMode::CENTERED, x...);
174 }
175
176 template<typename... Args>
177 auto traj_eval(const SampledTraj<Args>&... x) const
178 {
179 SampledTraj<typename T::Scalar> y;
180 for(const auto& [ti,xi] : std::get<0>(std::tie(x...)))
181 y.set(this->real_eval(x(ti)...),ti);
182 return y;
183 }
184
185 template<typename... Args>
186 auto tube_eval(const SlicedTube<Args>&... x) const
187 {
188 auto tdomain = std::get<0>(std::tie(x...)).tdomain();
189
190 SlicedTube<typename T::Domain> y(
191 tdomain, (typename T::Domain)(this->output_size())
192 );
193
194 for(auto it = tdomain->begin() ; it != tdomain->end() ; it++)
195 y.slice(it)->codomain() = this->eval(x.slice(it)->codomain()...);
196
197 return y;
198 }
199
200 template<typename... Args>
201 requires std::is_same_v<VectorType,T> && ((!std::is_same_v<MatrixType,typename ExprType<Args>::Type>) && ...)
202 Parallelepiped parallelepiped_eval(const Args&... x) const
203 {
204 this->check_valid_inputs(x...);
205 assert_release(this->input_size() < this->output_size() &&
206 "Parallelepiped evaluation requires more outputs than inputs.");
207 assert_release(this->input_size() > 0 &&
208 "Parallelepiped evaluation requires at least one input.");
209
210 IntervalVector Y = this->eval(((typename Wrapper<Args>::Domain)(x)).mid()...);
211 Vector z = Y.mid();
212
213 Matrix A = this->diff(((typename Wrapper<Args>::Domain)(x)).mid()...).mid();
214
215 // Maximum error computation
216 double rho = error_peibos(Y, z, this->diff(x...), A, cart_prod(x...));
217
218 // Inflation of the parallelepiped
219 Matrix A_inf = inflate_flat_parallelepiped(A, (cart_prod(x...).template cast<Interval>()).rad(), rho);
220
221 return Parallelepiped(z, A_inf);
222 }
223
224 Index output_size() const
225 {
226 if constexpr(std::is_same_v<T,ScalarType>)
227 return 1;
228
229 else {
230 std::pair<Index,Index> oshape = output_shape();
231 return oshape.first * oshape.second;
232 }
233 }
234
235 std::pair<Index,Index> output_shape() const
236 {
237 if constexpr(std::is_same_v<T,ScalarType>)
238 return {1,1};
239 else return this->expr()->output_shape();
240 }
241
242 friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction<T>& f)
243 {
244 os << "(";
245 for(size_t i = 0 ; i < f.args().size() ; i++)
246 os << (i!=0 ? "," : "") << f.args()[i]->name();
247 os << ") ↦ " << f.expr()->str();
248 return os;
249 }
250
251 // not working with Clang: template<typename Y, typename... X>
252 // not working with Clang: requires (sizeof...(X) > 0)
253 // not working with Clang: friend class CtcInverse;
254
255 // So, the following methods are temporarily public
256
257 // protected:
258
259 template<typename... Args>
260 void fill_from_args(ValuesMap& v, const Args&... x) const
261 {
262 Index i = 0;
263 (add_value_to_arg_map(v, x, i++), ...);
264 }
265
266 template<typename... Args>
267 void intersect_from_args(const ValuesMap& v, Args&... x) const
268 {
269 Index i = 0;
270 (intersect_value_from_arg_map(v, x, i++), ...);
271 }
272
273 protected:
274
275 template<typename D>
276 void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const
277 {
278 assert(i >= 0 && i < (Index)this->args().size());
279 assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs");
280
281 using D_TYPE = typename ExprType<D>::Type;
282
283 IntervalMatrix d = IntervalMatrix::zero(size_of(x), this->args().total_size());
284
285 Index p = 0;
286 for(Index j = 0 ; j < i ; j++)
287 p += this->args()[j]->size();
288
289 for(Index k = p ; k < p+size_of(x) ; k++)
290 d(k-p,k) = 1.;
291
292 v[this->args()[i]->unique_id()] =
293 std::make_shared<D_TYPE>(typename D_TYPE::Domain(x).mid(), x, d, true);
294 }
295
296 template<typename D>
297 void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const
298 {
299 assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found");
300 x &= std::dynamic_pointer_cast<typename ExprType<D>::Type>(v.at(this->args()[i]->unique_id()))->a;
301 }
302
303 template<bool NATURAL_EVAL,typename... Args>
304 auto eval_(const Args&... x) const
305 {
306 ValuesMap v;
307
308 if constexpr(sizeof...(Args) == 0)
309 return this->expr()->fwd_eval(v, 0, NATURAL_EVAL);
310
311 else
312 {
313 fill_from_args(v, x...);
314 return this->expr()->fwd_eval(v, cart_prod(x...).size(), NATURAL_EVAL); // todo: improve size computation
315 }
316 }
317
318 template<typename... Args>
319 void check_valid_inputs(const Args&... x) const
320 {
321 [[maybe_unused]] Index n = 0;
322 ((n += size_of(x)), ...);
323
324 assert_release(this->_args.total_size() == n &&
325 "Invalid arguments: wrong number of input arguments");
326 }
327
328 inline void update_var_names()
329 {
330 for(const auto& v : this->_args) // variable names are automatically computed in FunctionArgsList,
331 // so we propagate them to the expression
332 this->_y->replace_arg(v->unique_id(), std::dynamic_pointer_cast<ExprBase>(v));
333 }
334 };
335
336 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarExpr>) ->
337 AnalyticFunction<VectorType>;
338
339 template<typename T>
340 AnalyticFunction(const FunctionArgsList&, const T&) ->
341 AnalyticFunction<typename ExprType<T>::Type>;
342
343}
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
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