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"
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 update_var_names();
51 }
52
53 AnalyticFunction(const FunctionArgsList& args, const AnalyticExprWrapper<T>& y)
54 : FunctionBase<AnalyticExpr<T>>(args, y)
55 {
56 assert_release(y->belongs_to_args_list(this->args()) &&
57 "Invalid argument: variable not present in input arguments");
58 update_var_names();
59 }
60
61 AnalyticFunction(const AnalyticFunction<T>& f)
62 : FunctionBase<AnalyticExpr<T>>(f)
63 { }
64
65 template<typename... X>
66 AnalyticExprWrapper<T> operator()(const X&... x) const
67 {
68 return { this->FunctionBase<AnalyticExpr<T>>::operator()(x...) };
69 }
70
71 template<typename... Args>
72 auto real_eval(const Args&... x) const
73 {
74 return eval(x...).mid();
75 }
76
77 template<typename... Args>
78 typename T::Domain eval(const EvalMode& m, const Args&... x) const
79 {
80 check_valid_inputs(x...);
81
82 switch(m)
83 {
84 case EvalMode::NATURAL:
85 {
86 return eval_<true>(x...).a;
87 }
88
89 case EvalMode::CENTERED:
90 {
91 auto x_ = eval_<false>(x...);
92 auto flatten_x = IntervalVector(cart_prod(x...));
93 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
94
95 if constexpr(std::is_same_v<T,ScalarType>)
96 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0];
97
98 else if constexpr(std::is_same_v<T,VectorType>)
99 return x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0);
100
101 else
102 {
103 static_assert(std::is_same_v<T,MatrixType>);
104 return x_.m + (x_.da*(flatten_x-flatten_x.mid()))
105 .reshaped(x_.m.rows(), x_.m.cols());
106 }
107 }
108
109 case EvalMode::DEFAULT:
110 default:
111 {
112 auto x_ = eval_<false>(x...);
113
114 // If the centered form is not available for this expression...
115 if(x_.da.size() == 0 // .. because some parts have not yet been implemented,
116 || !x_.def_domain) // .. or due to restrictions in the derivative definition domain
117 return eval(EvalMode::NATURAL, x...);
118
119 else
120 {
121 auto flatten_x = IntervalVector(cart_prod(x...));
122
123 if constexpr(std::is_same_v<T,ScalarType>)
124 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid()))[0]);
125
126 else if constexpr(std::is_same_v<T,VectorType>)
127 {
128 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
129 return x_.a & (x_.m + (x_.da*(flatten_x-flatten_x.mid())).col(0));
130 }
131
132 else
133 {
134 static_assert(std::is_same_v<T,MatrixType>);
135 assert(x_.da.rows() == x_.a.size() && x_.da.cols() == flatten_x.size());
136 return x_.a & (x_.m +(x_.da*(flatten_x-flatten_x.mid()))
137 .reshaped(x_.m.rows(),x_.m.cols()));
138 }
139 }
140 }
141 }
142 }
143
144 template<typename... Args>
145 typename T::Domain eval(const Args&... x) const
146 {
147 return eval(EvalMode::NATURAL | EvalMode::CENTERED, x...);
148 }
149
150 template<typename... Args>
151 auto diff(const Args&... x) const
152 {
153 check_valid_inputs(x...);
154 return eval_<false>(x...).da;
155 }
156
157 Index output_size() const
158 {
159 if constexpr(std::is_same_v<T,ScalarType>)
160 return 1;
161
162 else {
163 std::pair<Index,Index> oshape = output_shape();
164 return oshape.first * oshape.second;
165 }
166 }
167
168 std::pair<Index,Index> output_shape() const
169 {
170 if constexpr(std::is_same_v<T,ScalarType>)
171 return {1,1};
172 else return this->expr()->output_shape();
173 }
174
175 friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction<T>& f)
176 {
177 os << "(";
178 for(size_t i = 0 ; i < f.args().size() ; i++)
179 os << (i!=0 ? "," : "") << f.args()[i]->name();
180 os << ") ↦ " << f.expr()->str();
181 return os;
182 }
183
184 protected:
185
186 template<typename Y>
187 friend class CtcInverse_;
188
189 template<typename D>
190 void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const
191 {
192 assert(i >= 0 && i < (Index)this->args().size());
193 assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs");
194
195 using D_TYPE = typename ValueType<D>::Type;
196
197 IntervalMatrix d = IntervalMatrix::zero(size_of(x), this->args().total_size());
198
199 Index p = 0;
200 for(Index j = 0 ; j < i ; j++)
201 p += this->args()[j]->size();
202
203 for(Index k = p ; k < p+size_of(x) ; k++)
204 d(k-p,k) = 1.;
205
206 v[this->args()[i]->unique_id()] =
207 std::make_shared<D_TYPE>(typename D_TYPE::Domain(x).mid(), x, d, true);
208 }
209
210 template<typename... Args>
211 void fill_from_args(ValuesMap& v, const Args&... x) const
212 {
213 Index i = 0;
214 (add_value_to_arg_map(v, x, i++), ...);
215 }
216
217 template<typename D>
218 void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const
219 {
220 assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found");
221 x &= std::dynamic_pointer_cast<typename ValueType<D>::Type>(v.at(this->args()[i]->unique_id()))->a;
222 }
223
224 template<typename... Args>
225 void intersect_from_args(const ValuesMap& v, Args&... x) const
226 {
227 Index i = 0;
228 (intersect_value_from_arg_map(v, x, i++), ...);
229 }
230
231 template<bool NATURAL_EVAL,typename... Args>
232 auto eval_(const Args&... x) const
233 {
234 ValuesMap v;
235
236 if constexpr(sizeof...(Args) == 0)
237 return this->expr()->fwd_eval(v, 0, NATURAL_EVAL);
238
239 else
240 {
241 fill_from_args(v, x...);
242 return this->expr()->fwd_eval(v, cart_prod(x...).size(), NATURAL_EVAL); // todo: improve size computation
243 }
244 }
245
246 template<typename... Args>
247 void check_valid_inputs(const Args&... x) const
248 {
249 [[maybe_unused]] Index n = 0;
250 ((n += size_of(x)), ...);
251
252 assert_release(this->_args.total_size() == n &&
253 "Invalid arguments: wrong number of input arguments");
254 }
255
256 inline void update_var_names()
257 {
258 for(const auto& v : this->_args) // variable names are automatically computed in FunctionArgsList,
259 // so we propagate them to the expression
260 this->_y->replace_arg(v->unique_id(), std::dynamic_pointer_cast<ExprBase>(v));
261 }
262 };
263
264 AnalyticFunction(const FunctionArgsList&, std::initializer_list<ScalarExpr>) ->
265 AnalyticFunction<VectorType>;
266
267 template<typename T>
268 AnalyticFunction(const FunctionArgsList&, const T&) ->
269 AnalyticFunction<typename ValueType<T>::Type>;
270
271}
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:208
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:207
const std::shared_ptr< AnalyticExpr< T > > & expr() const
Definition codac2_FunctionBase.h:103