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"
23
24namespace codac2
25{
26 enum class EvalMode
27 {
28 NATURAL = 0x01,
29 CENTERED = 0x02,
30 DEFAULT = 0x03 // corresponds to (NATURAL|CENTERED)
31 };
32
33 inline EvalMode operator&(EvalMode a, EvalMode b)
34 { return static_cast<EvalMode>(static_cast<int>(a) & static_cast<int>(b)); }
35
36 inline EvalMode operator|(EvalMode a, EvalMode b)
37 { return static_cast<EvalMode>(static_cast<int>(a) | static_cast<int>(b)); }
38
39 struct ScalarExprList : public AnalyticExprWrapper<VectorType>
40 {
41 // Mainly used to take advantage of initializer lists in AnalyticFunction constructors.
42 template<typename... S>
43 requires (std::is_same_v<typename ExprType<S>::Type,ScalarType> && ...)
44 ScalarExprList(const S&... y)
45 : AnalyticExprWrapper<VectorType>(vec(y...))
46 { }
47 };
48
49 template<typename T>
50 class SampledTraj;
51
52 template<typename T>
53 class SlicedTube;
54
55 template<typename T>
56 requires std::is_base_of_v<AnalyticTypeBase,T>
57 class AnalyticFunction : public FunctionBase<AnalyticExpr<T>>
58 {
59 public:
60
61 AnalyticFunction(const FunctionArgsList& args, const ScalarExprList& y)
62 requires(std::is_same_v<T,VectorType>)
63 : FunctionBase<AnalyticExpr<T>>(args, y)
64 {
65 assert_release(y->belongs_to_args_list(this->args()) &&
66 "Invalid argument: variable not present in input arguments");
67 update_var_names();
68 }
69
70 AnalyticFunction(const FunctionArgsList& args, const AnalyticExprWrapper<T>& y)
71 : FunctionBase<AnalyticExpr<T>>(args, y)
72 {
73 assert_release(y->belongs_to_args_list(this->args()) &&
74 "Invalid argument: variable not present in input arguments");
75 update_var_names();
76 }
77
78 AnalyticFunction(const AnalyticFunction<T>& f)
79 : FunctionBase<AnalyticExpr<T>>(f)
80 { }
81
82 template<typename... X>
83 AnalyticExprWrapper<T> operator()(const X&... x) const
84 {
85 return { this->FunctionBase<AnalyticExpr<T>>::operator()(x...) };
86 }
87
88 template<typename... Args>
89 auto real_eval(const Args&... x) const
90 {
91 return eval(x...).mid();
92 }
93
94 template<typename... Args>
95 typename T::Domain eval(const EvalMode& m, const Args&... x) const
96 {
97 check_valid_inputs(x...);
98
99 switch(m)
100 {
101 case EvalMode::NATURAL:
102 {
103 return eval_<true>(x...).a;
104 }
105
106 case EvalMode::CENTERED:
107 {
108 auto x_ = eval_<false>(x...);
109 auto flatten_x = IntervalVector(cart_prod(x...));
110 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
111
112 if constexpr(std::is_same_v<T,ScalarType>)
113 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0];
114
115 else if constexpr(std::is_same_v<T,VectorType>)
116 return x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0);
117
118 else
119 {
120 static_assert(std::is_same_v<T,MatrixType>);
121 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))
122 .reshaped(x_.m.rows(), x_.m.cols());
123 }
124 }
125
126 case EvalMode::DEFAULT:
127 default:
128 {
129 auto x_ = eval_<false>(x...);
130
131 // If the centered form is not available for this expression...
132 if(x_.da.size() == 0 // .. because some parts have not yet been implemented,
133 || !x_.def_domain) // .. or due to restrictions in the derivative definition domain
134 return eval(EvalMode::NATURAL, x...);
135
136 else
137 {
138 auto flatten_x = IntervalVector(cart_prod(x...));
139
140 if constexpr(std::is_same_v<T,ScalarType>)
141 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0]);
142
143 else if constexpr(std::is_same_v<T,VectorType>)
144 {
145 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
146 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0));
147 }
148
149 else
150 {
151 static_assert(std::is_same_v<T,MatrixType>);
152 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
153 return x_.a & (x_.m +(x_.da*(flatten_x-flatten_x.mid()))
154 .reshaped(x_.m.rows(),x_.m.cols()));
155 }
156 }
157 }
158 }
159 }
160
161 template<typename... Args>
162 auto diff(const Args&... x) const
163 {
164 check_valid_inputs(x...);
165 return eval_<false>(x...).da;
166 }
167
168 template<typename... Args>
169 typename T::Domain eval(const Args&... x) const
170 {
171 return eval(EvalMode::NATURAL | EvalMode::CENTERED, x...);
172 }
173
174 template<typename... Args>
175 auto traj_eval(const SampledTraj<Args>&... x) const
176 {
177 SampledTraj<typename T::Scalar> y;
178 for(const auto& [ti,xi] : std::get<0>(std::tie(x...)))
179 y.set(this->real_eval(x(ti)...),ti);
180 return y;
181 }
182
183 template<typename... Args>
184 auto tube_eval(const SlicedTube<Args>&... x) const
185 {
186 auto tdomain = std::get<0>(std::tie(x...)).tdomain();
187
188 SlicedTube<typename T::Domain> y(
189 tdomain, (typename T::Domain)(this->output_size())
190 );
191
192 for(auto it = tdomain->begin() ; it != tdomain->end() ; it++)
193 y(it)->codomain() = this->eval(x(it)->codomain()...);
194
195 return y;
196 }
197
198 template<typename... Args>
199 Parallelepiped parallelepiped_eval(const Args&... x) const;
200 // -> is defined in codac2_Parallelepiped_eval.h file
201
202 Index output_size() const
203 {
204 if constexpr(std::is_same_v<T,ScalarType>)
205 return 1;
206
207 else {
208 std::pair<Index,Index> oshape = output_shape();
209 return oshape.first * oshape.second;
210 }
211 }
212
213 std::pair<Index,Index> output_shape() const
214 {
215 if constexpr(std::is_same_v<T,ScalarType>)
216 return {1,1};
217 else return this->expr()->output_shape();
218 }
219
220 friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction<T>& f)
221 {
222 os << "(";
223 for(size_t i = 0 ; i < f.args().size() ; i++)
224 os << (i!=0 ? "," : "") << f.args()[i]->name();
225 os << ") ↦ " << f.expr()->str();
226 return os;
227 }
228
229 // not working with Clang: template<typename Y, typename... X>
230 // not working with Clang: requires (sizeof...(X) > 0)
231 // not working with Clang: friend class CtcInverse;
232
233 // So, the following methods are temporarily public
234
235 // protected:
236
237 template<typename... Args>
238 void fill_from_args(ValuesMap& v, const Args&... x) const
239 {
240 Index i = 0;
241 (add_value_to_arg_map(v, x, i++), ...);
242 }
243
244 template<typename... Args>
245 void intersect_from_args(const ValuesMap& v, Args&... x) const
246 {
247 Index i = 0;
248 (intersect_value_from_arg_map(v, x, i++), ...);
249 }
250
251 protected:
252
253 template<typename D>
254 void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const
255 {
256 assert(i >= 0 && i < (Index)this->args().size());
257 assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs");
258
259 using D_TYPE = typename ExprType<D>::Type;
260
261 IntervalMatrix d = IntervalMatrix::zero(size_of(x), this->args().total_size());
262
263 Index p = 0;
264 for(Index j = 0 ; j < i ; j++)
265 p += this->args()[j]->size();
266
267 for(Index k = p ; k < p+size_of(x) ; k++)
268 d(k-p,k) = 1.;
269
270 v[this->args()[i]->unique_id()] =
271 std::make_shared<D_TYPE>(typename D_TYPE::Domain(x).mid(), x, d, true);
272 }
273
274 template<typename D>
275 void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const
276 {
277 assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found");
278 x &= std::dynamic_pointer_cast<typename ExprType<D>::Type>(v.at(this->args()[i]->unique_id()))->a;
279 }
280
281 template<bool NATURAL_EVAL,typename... Args>
282 auto eval_(const Args&... x) const
283 {
284 ValuesMap v;
285
286 if constexpr(sizeof...(Args) == 0)
287 return this->expr()->fwd_eval(v, 0, NATURAL_EVAL);
288
289 else
290 {
291 fill_from_args(v, x...);
292 return this->expr()->fwd_eval(v, cart_prod(x...).size(), NATURAL_EVAL); // todo: improve size computation
293 }
294 }
295
296 template<typename... Args>
297 void check_valid_inputs(const Args&... x) const
298 {
299 [[maybe_unused]] Index n = 0;
300 ((n += size_of(x)), ...);
301
302 assert_release(this->_args.total_size() == n &&
303 "Invalid arguments: wrong number of input arguments");
304 }
305
306 inline void update_var_names()
307 {
308 for(const auto& v : this->_args) // variable names are automatically computed in FunctionArgsList,
309 // so we propagate them to the expression
310 this->_y->replace_arg(v->unique_id(), std::dynamic_pointer_cast<ExprBase>(v));
311 }
312 };
313
314 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarExpr>) ->
315 AnalyticFunction<VectorType>;
316
317 template<typename T>
318 AnalyticFunction(const FunctionArgsList&, const T&) ->
319 AnalyticFunction<typename ExprType<T>::Type>;
320
321}
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
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< Interval,-1, 1 > IntervalVector
Alias for a dynamic-size column vector of intervals.
Definition codac2_IntervalVector.h:25
Eigen::Matrix< Interval,-1,-1 > IntervalMatrix
Alias for a dynamic-size matrix of intervals.
Definition codac2_IntervalMatrix.h:25