fmatvec  0.0.0
ast.h
1#ifndef _FMATVEC_AST_H_
2#define _FMATVEC_AST_H_
3
4#include "fmatvec/function.h"
5#include <map>
6#include <array>
7#include <memory>
8#include <boost/uuid/uuid.hpp>
9#include <boost/uuid/uuid_generators.hpp>
10#include <boost/container/small_vector.hpp>
11#include <utility>
12#include <fmatvec/stream.h>
13
14namespace fmatvec {
15FMATVEC_MSVC_DISABLEW4251_BEGIN
16
17// forward declarations
18
19class IndependentVariable;
20
21namespace AST {
22 class Vertex;
23 class Symbol;
24 class Operation;
25 class NativeFunction;
26 template<class T> class Constant;
27 FMATVEC_EXPORT SymbolicExpression substScalar(const SymbolicExpression &se, const IndependentVariable& a, const SymbolicExpression &b);
28}
29
30template<class... Arg> class Eval;
31class EvalHelper;
32
38class FMATVEC_EXPORT SymbolicExpression : public std::shared_ptr<const AST::Vertex> {
39 template<class... Arg> friend class Eval;
40 friend class EvalHelper;
41 friend class AST::Operation;
42 friend class AST::Constant<long>;
43 friend class AST::Constant<double>;
44 friend class AST::NativeFunction;
45 friend FMATVEC_EXPORT SymbolicExpression parDer(const SymbolicExpression &dep, const IndependentVariable &indep);
46 friend SymbolicExpression AST::substScalar(const SymbolicExpression &se,
47 const IndependentVariable& a, const SymbolicExpression &b);
48 protected:
49 template<class T> SymbolicExpression(const shared_ptr<T> &x);
50#ifndef SWIG
51 static const struct ConstructSymbol{} constructSymbol; // just used for tag dispatching
52#endif
53 SymbolicExpression(ConstructSymbol);
54
55 // do not allow to call these functions inherited from std::shared_ptr
56 using std::shared_ptr<const AST::Vertex>::get;
57 using std::shared_ptr<const AST::Vertex>::operator*;
58 using std::shared_ptr<const AST::Vertex>::operator->;
59 public:
63 SymbolicExpression(const std::string &str);
65 SymbolicExpression(int x);
66 SymbolicExpression(long x);
68 SymbolicExpression(double x);
69
73 static void garbageCollect();
74
75 // default ctors and assignment operators
76 SymbolicExpression(const SymbolicExpression& x) = default;
78 SymbolicExpression& operator=(const SymbolicExpression& x) = default;
79 SymbolicExpression& operator=(SymbolicExpression&& x) = default;
80 ~SymbolicExpression() = default;
81
82 // operators
83#ifndef SWIG
84 SymbolicExpression operator+(const SymbolicExpression &b) const;
85 SymbolicExpression operator-(const SymbolicExpression &b) const;
86 SymbolicExpression operator*(const SymbolicExpression &b) const;
87 SymbolicExpression operator/(const SymbolicExpression &b) const;
88#endif
89 SymbolicExpression operator-() const;
90 SymbolicExpression& operator+=(const SymbolicExpression &b);
91 SymbolicExpression& operator-=(const SymbolicExpression &b);
92 SymbolicExpression& operator*=(const SymbolicExpression &b);
93 SymbolicExpression& operator/=(const SymbolicExpression &b);
94
95 // We implement operator<<= to be able to use SymbolicExpression fully equivalent to the vector/matrix classes
96 // which have a assign method which redimension before assigning. Redimensioning is not required for a scalar
97 // type like assign
98 SymbolicExpression& operator<<=(const SymbolicExpression &src);
99
100#if defined(FMATVEC_DEBUG) && !defined(SWIG)
101 static signed long evalOperationsCount;
102#endif
103};
104
108class FMATVEC_EXPORT IndependentVariable : public SymbolicExpression {
109 friend class AST::Symbol;
110 friend FMATVEC_EXPORT std::istream& operator>>(std::istream& s, IndependentVariable &v);
111 public:
115 IndependentVariable(const std::string &str);
116
117#ifndef SWIG
119 inline IndependentVariable& operator^=(double x);
120#endif
121
122 private:
123 IndependentVariable(const shared_ptr<const AST::Symbol> &x);
124};
125
126// define the operator results of SymbolicExpression and IndependentVariable with other AT types.
127FMATVEC_OPERATORRESULT1(SymbolicExpression, SymbolicExpression)
128
129FMATVEC_OPERATORRESULT2(SymbolicExpression, int, SymbolicExpression)
130FMATVEC_OPERATORRESULT2(SymbolicExpression, long, SymbolicExpression)
131FMATVEC_OPERATORRESULT2(SymbolicExpression, double, SymbolicExpression)
132
133FMATVEC_OPERATORRESULT1(IndependentVariable, SymbolicExpression)
134
135FMATVEC_OPERATORRESULT2(IndependentVariable, int, SymbolicExpression)
136FMATVEC_OPERATORRESULT2(IndependentVariable, long, SymbolicExpression)
137FMATVEC_OPERATORRESULT2(IndependentVariable, double, SymbolicExpression)
139
140// Some member function definition of SymbolicExpression/IndependentVariable are moved to the end of this file
141// since they need the defintion of the other class defined in this file.
142
143FMATVEC_EXPORT SymbolicExpression operator+(double a, const SymbolicExpression &b);
144FMATVEC_EXPORT SymbolicExpression operator-(double a, const SymbolicExpression &b);
145FMATVEC_EXPORT SymbolicExpression operator*(double a, const SymbolicExpression &b);
146FMATVEC_EXPORT SymbolicExpression operator/(double a, const SymbolicExpression &b);
147FMATVEC_EXPORT SymbolicExpression operator+(int a, const SymbolicExpression &b);
148FMATVEC_EXPORT SymbolicExpression operator-(int a, const SymbolicExpression &b);
149FMATVEC_EXPORT SymbolicExpression operator*(int a, const SymbolicExpression &b);
150FMATVEC_EXPORT SymbolicExpression operator/(int a, const SymbolicExpression &b);
151FMATVEC_EXPORT SymbolicExpression operator+(long a, const SymbolicExpression &b);
152FMATVEC_EXPORT SymbolicExpression operator-(long a, const SymbolicExpression &b);
153FMATVEC_EXPORT SymbolicExpression operator*(long a, const SymbolicExpression &b);
154FMATVEC_EXPORT SymbolicExpression operator/(long a, const SymbolicExpression &b);
155
158FMATVEC_EXPORT SymbolicExpression parDer(const SymbolicExpression &dep, const IndependentVariable &indep);
159
161FMATVEC_EXPORT std::ostream& operator<<(std::ostream& s, const SymbolicExpression& se);
163FMATVEC_EXPORT std::istream& operator>>(std::istream& s, SymbolicExpression &se);
165FMATVEC_EXPORT std::istream& operator>>(std::istream& s, IndependentVariable &v);
166
167// function operations overloaded for SymbolicExpression
168FMATVEC_EXPORT SymbolicExpression pow(const SymbolicExpression &a, const SymbolicExpression &b);
169FMATVEC_EXPORT SymbolicExpression log(const SymbolicExpression &a);
170FMATVEC_EXPORT SymbolicExpression sqrt(const SymbolicExpression &a);
171FMATVEC_EXPORT SymbolicExpression sin(const SymbolicExpression &a);
172FMATVEC_EXPORT SymbolicExpression cos(const SymbolicExpression &a);
173FMATVEC_EXPORT SymbolicExpression tan(const SymbolicExpression &a);
174FMATVEC_EXPORT SymbolicExpression sinh(const SymbolicExpression &a);
175FMATVEC_EXPORT SymbolicExpression cosh(const SymbolicExpression &a);
176FMATVEC_EXPORT SymbolicExpression tanh(const SymbolicExpression &a);
177FMATVEC_EXPORT SymbolicExpression asin(const SymbolicExpression &a);
178FMATVEC_EXPORT SymbolicExpression acos(const SymbolicExpression &a);
179FMATVEC_EXPORT SymbolicExpression atan(const SymbolicExpression &a);
180FMATVEC_EXPORT SymbolicExpression atan2(const SymbolicExpression &y, const SymbolicExpression &x);
181FMATVEC_EXPORT SymbolicExpression asinh(const SymbolicExpression &a);
182FMATVEC_EXPORT SymbolicExpression acosh(const SymbolicExpression &a);
183FMATVEC_EXPORT SymbolicExpression atanh(const SymbolicExpression &a);
184FMATVEC_EXPORT SymbolicExpression exp(const SymbolicExpression &a);
185FMATVEC_EXPORT SymbolicExpression sign(const SymbolicExpression &a);
186FMATVEC_EXPORT SymbolicExpression heaviside(const SymbolicExpression &a);
187FMATVEC_EXPORT SymbolicExpression abs(const SymbolicExpression &a);
188FMATVEC_EXPORT SymbolicExpression min(const SymbolicExpression &a, const SymbolicExpression &b);
189FMATVEC_EXPORT SymbolicExpression max(const SymbolicExpression &a, const SymbolicExpression &b);
190FMATVEC_EXPORT SymbolicExpression condition(const SymbolicExpression &c, const SymbolicExpression &gt, const SymbolicExpression &lt);
191
192#ifndef SWIG
193namespace AST { // internal namespace
194
195/* ***** Struct for a "bytecode" for fast runtime evaluation *****
196 * This class uses very low-level technices like raw-pointers to gain maximal performance
197 * during runtime evaluation.
198 *
199 * This class store a kind of "bytecode" which can be used to evaluate an mathematical expression very fast.
200 * This class is not copyable and not moveable since it uses intern pointers between instances of this class.
201 * For optimal performance this class should be used in continous memory e.g. as std::vector<ByteCode>.
202 * For the same reason, to keep all data near together for best processor memory cache usage, all members
203 * of these class also to not use allocated memory: std::array instead of std::vector is used.
204 * The usage of std::vector<ByteCode> requires that the move-ctor must be provided at compile time
205 * (it cannot be delete'd) but the move-ctor throws at runtime when called to ensure its not used.
206 * Hence std::vector<ByteCode> can only be used without reallocation: std::vector::reserve must be called before use.
207 * To add an element only std::vector::emplace_back() can be used.
208*/
209struct FMATVEC_EXPORT ByteCode {
210 static constexpr size_t N { 12 };
211 ByteCode(size_t n);
212 ByteCode(const ByteCode &) = delete;
213 ByteCode(ByteCode &&) noexcept;
214 ByteCode &operator=(const ByteCode &) = delete;
215 ByteCode &operator=(ByteCode &&) = delete;
216 ~ByteCode() = default;
217 using Arg = boost::container::small_vector<double*,N>;
218 std::function<void(double*, const Arg&)> func; // the operation this byteCode entry executes
219 double retValue; // storage of the return value of the operation: retPtr may point to this value
220 double* retPtr; // a pointer to which the operation can write its result to
221 Arg argsPtr; // pointers from which the operation reads its arguments
222};
223
224template<class Func, class ArgS>
226 static SymbolicExpression call(
227 const std::shared_ptr<Function<Func>> &func,
228 const ArgS &arg);
229};
230
231template<>
233 static SymbolicExpression call(
234 const std::shared_ptr<Function<double(double)>> &func,
235 const SymbolicExpression &arg);
236};
237
238template<class Type>
239struct SymbolicFuncWrapArg1<double(Vector<Type, double>), Vector<Type, SymbolicExpression>> {
240 static SymbolicExpression call(
241 const std::shared_ptr<Function<double(Vector<Type, double>)>> &func,
243};
244
245template<class Func, class Arg1S, class Arg2S>
247 static SymbolicExpression call(
248 const std::shared_ptr<Function<Func>> &func,
249 const Arg1S &arg1, const Arg2S &arg2);
250};
251
252template<>
254 static SymbolicExpression call(
255 const std::shared_ptr<Function<double(double,double)>> &func,
256 const SymbolicExpression &arg1, const SymbolicExpression &arg2);
257};
258
259template<class Type>
260struct SymbolicFuncWrapArg2<double(Vector<Type,double>,double), Vector<Type, SymbolicExpression>, SymbolicExpression> {
261 static SymbolicExpression call(
262 const std::shared_ptr<Function<double(Vector<Type,double>,double)>> &func,
264};
265
266template<class Type>
267struct SymbolicFuncWrapArg2<double(double,Vector<Type,double>), SymbolicExpression, Vector<Type, SymbolicExpression>> {
268 static SymbolicExpression call(
269 const std::shared_ptr<Function<double(double,Vector<Type,double>)>> &func,
271};
272
273template<class Type1, class Type2>
274struct SymbolicFuncWrapArg2<double(Vector<Type1,double>,Vector<Type2,double>), Vector<Type1, SymbolicExpression>, Vector<Type2, SymbolicExpression>> {
275 static SymbolicExpression call(
278};
279
280// ***** Vertex *****
281
283class FMATVEC_EXPORT Vertex {
284 friend Operation;
285 friend NativeFunction;
286 public:
287 virtual ~Vertex() = default;
288
292 inline virtual bool isConstantInt() const;
295 bool isZero() const;
298 bool isOne() const;
299
300 virtual std::vector<ByteCode>::iterator dumpByteCode(std::vector<ByteCode> &byteCode,
301 std::map<const Vertex*, std::vector<AST::ByteCode>::iterator> &existingVertex) const=0;
302
303 virtual void walkVertex(const std::function<void(const std::shared_ptr<const Vertex>&)> &func) const=0;
304
305 protected:
306
307 // helper function to make it easy to implement new expression optimizations. See ast.cc Operation::create for details.
308 // Returns true if this Vertex the Vertex (SymbolicExpression) b. Every Symbol variables in this Vertex are free. This
309 // means that true is also returned if the Symbols in this Vertex can be replaced by anything such that the expressions
310 // are equal. All these required replacements are stored in m.
311 // NOTE:
312 // We define our own less operator for std::map<IndependentVariable, ...> since we abort in the overloaded function
313 // inline bool operator<(const fmatvec::SymbolicExpression& a, const fmatvec::SymbolicExpression& b) noexcept,
314 // see below. This abort is needed to avoid that e.g. std::min/std::max can be called with SymbolicExpression arguments.
315 // If your code calls this abort function you may call somewhere std::min(SymbolicExpression, SymbolicExpression) instead of
316 // fmatvec::min(SymbolicExpression, SymbolicExpression). The same applies for std::max/fmatvec::max.
317 // I was not able to solve this in a better way!
318 struct LessIV {
319 bool operator()(const IndependentVariable& a, const IndependentVariable& b) const {
320 return a.std::shared_ptr<const AST::Vertex>::get() < b.std::shared_ptr<const AST::Vertex>::get();
321 }
322 };
323 using MapIVSE = std::map<IndependentVariable, SymbolicExpression, LessIV>;
324 virtual bool equal(const SymbolicExpression &b, MapIVSE &m) const=0;
325};
326
327inline bool Vertex::isConstantInt() const {
328 return false;
329}
330
331// ***** Constant *****
332
334template<class T>
335class FMATVEC_EXPORT Constant : public Vertex, public std::enable_shared_from_this<Constant<T>> {
336 friend SymbolicExpression;
337 public:
338
339 static SymbolicExpression create(const T& c_);
340 SymbolicExpression parDer(const IndependentVariable &x) const override;
341 inline bool isConstantInt() const override;
343 inline const T& getValue() const;
344 std::vector<ByteCode>::iterator dumpByteCode(std::vector<ByteCode> &byteCode,
345 std::map<const Vertex*, std::vector<AST::ByteCode>::iterator> &existingVertex) const override;
346
347 void walkVertex(const std::function<void(const std::shared_ptr<const Vertex>&)> &func) const override;
348
349 private:
350
351 Constant(const T& c_);
352 const T c;
353 bool equal(const SymbolicExpression &b, MapIVSE &m) const override;
354 using CacheKey = T;
355 static std::map<CacheKey, std::weak_ptr<const Constant>> cache;
356};
357
358template<>
360 return false;
361}
362
363template<>
364inline bool Constant<long>::isConstantInt() const {
365 return true;
366}
367
368template<class T>
369const T& Constant<T>::getValue() const {
370 return c;
371}
372
373// ***** Symbol *****
374
376class FMATVEC_EXPORT Symbol : public Vertex, public std::enable_shared_from_this<Symbol> {
377 friend SymbolicExpression;
378 friend IndependentVariable;
379 public:
380
381 static IndependentVariable create(const boost::uuids::uuid& uuid_=boost::uuids::random_generator()());
382 SymbolicExpression parDer(const IndependentVariable &x) const override;
385 inline void setValue(double x_) const;
386
387 std::string getUUIDStr() const;
388
389 std::vector<ByteCode>::iterator dumpByteCode(std::vector<ByteCode> &byteCode,
390 std::map<const Vertex*, std::vector<AST::ByteCode>::iterator> &existingVertex) const override;
391
392 void walkVertex(const std::function<void(const std::shared_ptr<const Vertex>&)> &func) const override;
393
394 private:
395
396 Symbol(const boost::uuids::uuid& uuid_);
397 bool equal(const SymbolicExpression &b, MapIVSE &m) const override;
398 mutable double x = 0.0;
399 boost::uuids::uuid uuid; // each variable has a uuid (this is only used when the AST is serialized and for caching)
400 using CacheKey = boost::uuids::uuid;
401 static std::map<CacheKey, std::weak_ptr<const Symbol>> cache;
402};
403
404void Symbol::setValue(double x_) const {
405 x=x_;
406}
407
408// ***** ScalarFunctionWrapArg *****
409
411 public:
412 virtual ~ScalarFunctionWrapArg() = default;
413 virtual double operator()(const ByteCode::Arg &arg) = 0;
414 virtual double dirDer(const ByteCode::Arg &arg) = 0;
415 virtual double dirDerDirDer(const ByteCode::Arg &arg) = 0;
416};
417
419 public:
420 ScalarFunctionWrapArgS(std::shared_ptr<fmatvec::Function<double(double)>> func_) : func(std::move(func_)) {}
421 double operator()(const ByteCode::Arg &arg) override {
422 return (*func)(*arg[0]);
423 }
424 double dirDer(const ByteCode::Arg &arg) override {
425 return func->dirDer(*arg[1], *arg[0]);
426 }
427 double dirDerDirDer(const ByteCode::Arg &arg) override {
428 return func->dirDerDirDer(*arg[1], *arg[2], *arg[0]);
429 }
430 private:
431 std::shared_ptr<fmatvec::Function<double(double)>> func;
432};
433
434template<class Type>
436 public:
437 ScalarFunctionWrapArgV(const std::shared_ptr<fmatvec::Function<double(fmatvec::Vector<Type,double>)>> &func_, int argSize) : func(func_) {
438 argV.resize(argSize);
439 dir1V.resize(argSize);
440 dir2V.resize(argSize);
441 }
442 double operator()(const ByteCode::Arg &arg) override {
443 for(size_t i=0; i<argV.size(); ++i)
444 argV(i) = *arg[i];
445 return (*func)(argV);
446 }
447 double dirDer(const ByteCode::Arg &arg) override {
448 size_t argVsize=argV.size();
449 for(size_t i=0; i<argVsize; ++i)
450 argV(i) = *arg[i];
451 for(size_t i=0; i<argVsize; ++i)
452 dir1V(i) = *arg[i+argVsize];
453 return func->dirDer(dir1V, argV);
454 }
455 double dirDerDirDer(const ByteCode::Arg &arg) override {
456 size_t argVsize=argV.size();
457 for(size_t i=0; i<argVsize; ++i)
458 argV(i) = *arg[i];
459 for(size_t i=0; i<argVsize; ++i)
460 dir1V(i) = *arg[i+argVsize];
461 for(size_t i=0; i<argVsize; ++i)
462 dir2V(i) = *arg[i+2*argVsize];
463 return func->dirDerDirDer(dir1V, dir2V, argV);
464 }
465 private:
470};
471
473 public:
474 ScalarFunctionWrapArgSS(std::shared_ptr<fmatvec::Function<double(double,double)>> func_) : func(std::move(func_)) {}
475 double operator()(const ByteCode::Arg &arg) override {
476 return (*func)(*arg[0], *arg[1]);
477 }
478 double dirDer(const ByteCode::Arg &arg) override {
479 return func->dirDer1(*arg[2], *arg[0], *arg[1]) +
480 func->dirDer2(*arg[3], *arg[0], *arg[1]);
481 }
482 double dirDerDirDer(const ByteCode::Arg &arg) override {
483 return func->dirDer1DirDer1(*arg[2], *arg[4], *arg[0], *arg[1]) +
484 func->dirDer2DirDer1(*arg[5], *arg[2], *arg[0], *arg[1]) +
485 func->dirDer2DirDer1(*arg[3], *arg[4], *arg[0], *arg[1]) +
486 func->dirDer2DirDer2(*arg[3], *arg[5], *arg[0], *arg[1]);
487 }
488 private:
489 std::shared_ptr<fmatvec::Function<double(double,double)>> func;
490};
491
492template<class Type>
494 public:
495 ScalarFunctionWrapArgVS(const std::shared_ptr<fmatvec::Function<double(Vector<Type,double>,double)>> &func_, int argSize) : func(func_) {
496 argV.resize(argSize);
497 dir1V.resize(argSize);
498 dir2V.resize(argSize);
499 }
500 double operator()(const ByteCode::Arg &arg) override {
501 for(size_t i=0; i<argV.size(); ++i)
502 argV(i) = *arg[i];
503 return (*func)(argV, *arg[argV.size()]);
504 }
505 double dirDer(const ByteCode::Arg &arg) override {
506 auto argVsize=argV.size();
507 for(size_t i=0; i<argVsize; ++i)
508 argV(i) = *arg[i];
509 for(size_t i=0; i<argVsize; ++i)
510 dir1V(i) = *arg[i+1+argVsize];
511 return func->dirDer1(dir1V , argV, *arg[argVsize]) +
512 func->dirDer2(*arg[2*argVsize+1], argV, *arg[argVsize]);
513 }
514 double dirDerDirDer(const ByteCode::Arg &arg) override {
515 auto argVsize=argV.size();
516 for(size_t i=0; i<argVsize; ++i)
517 argV(i) = *arg[i];
518 for(size_t i=0; i<argVsize; ++i)
519 dir1V(i) = *arg[i+1+argVsize];
520 for(size_t i=0; i<argVsize; ++i)
521 dir2V(i) = *arg[i+2+2*argVsize];
522 return func->dirDer1DirDer1(dir1V, dir2V, argV, *arg[argVsize]) +
523 func->dirDer2DirDer1(*arg[1+2*argVsize], dir2V , argV, *arg[argVsize]) +
524 func->dirDer2DirDer1(*arg[2+3*argVsize], dir1V , argV, *arg[argVsize]) +
525 func->dirDer2DirDer2(*arg[1+2*argVsize], *arg[2+3*argVsize], argV, *arg[argVsize]);
526 }
527 private:
532};
533
534template<class Type>
536 public:
537 ScalarFunctionWrapArgSV(const std::shared_ptr<fmatvec::Function<double(double,Vector<Type,double>)>> &func_, int argSize) : func(func_) {
538 argV.resize(argSize);
539 dir1V.resize(argSize);
540 dir2V.resize(argSize);
541 }
542 double operator()(const ByteCode::Arg &arg) override {
543 for(size_t i=0; i<argV.size(); ++i)
544 argV(i) = *arg[i+1];
545 return (*func)(*arg[0], argV);
546 }
547 double dirDer(const ByteCode::Arg &arg) override {
548 auto argVsize=argV.size();
549 for(size_t i=0; i<argVsize; ++i)
550 argV(i) = *arg[i+1];
551 for(size_t i=0; i<argVsize; ++i)
552 dir1V(i) = *arg[i+2+argVsize];
553 return func->dirDer1(*arg[argVsize+1], *arg[0], argV) +
554 func->dirDer2(dir1V , *arg[0], argV);
555 }
556 double dirDerDirDer(const ByteCode::Arg &arg) override {
557 auto argVsize=argV.size();
558 for(size_t i=0; i<argVsize; ++i)
559 argV(i) = *arg[i+1];
560 for(size_t i=0; i<argVsize; ++i)
561 dir1V(i) = *arg[i+2+argVsize];
562 for(size_t i=0; i<argVsize; ++i)
563 dir2V(i) = *arg[i+3+2*argVsize];
564 return func->dirDer1DirDer1(*arg[argVsize+1], *arg[2*argVsize+2], *arg[0], argV) +
565 func->dirDer2DirDer1(dir2V , *arg[argVsize+1] , *arg[0], argV) +
566 func->dirDer2DirDer1(dir1V , *arg[2*argVsize+2], *arg[0], argV) +
567 func->dirDer2DirDer2(dir1V , dir2V , *arg[0], argV);
568 }
569 private:
574};
575
576template<class Type1, class Type2>
578 public:
580 int argaSize, int argbSize) : func(func_) {
581 argV1.resize(argaSize);
582 argV2.resize(argbSize);
583 dir1V1.resize(argaSize);
584 dir1V2.resize(argbSize);
585 dir2V1.resize(argaSize);
586 dir2V2.resize(argbSize);
587 }
588 double operator()(const ByteCode::Arg &arg) override {
589 auto argV1size = argV1.size();
590 auto argV2size = argV2.size();
591 for(int i=0; i<argV1size; ++i)
592 argV1(i)=*arg[i];
593 for(int i=0; i<argV2size; ++i)
594 argV2(i)=*arg[argV1size+i];
595 return (*func)(argV1, argV2);
596 }
597 double dirDer(const ByteCode::Arg &arg) override {
598 auto argV1size = argV1.size();
599 auto argV2size = argV2.size();
600 for(int i=0; i<argV1size; ++i)
601 argV1(i)=*arg[i];
602 for(int i=0; i<argV2size; ++i)
603 argV2(i)=*arg[argV1size+i];
604 for(size_t i=0; i<argV1size; ++i)
605 dir1V1(i) = *arg[argV1size+argV2size+i];
606 for(size_t i=0; i<argV2size; ++i)
607 dir1V2(i) = *arg[2*argV1size+argV2size+i];
608 return func->dirDer1(dir1V1, argV1, argV2) +
609 func->dirDer2(dir1V2, argV1, argV2);
610 }
611 double dirDerDirDer(const ByteCode::Arg &arg) override {
612 auto argV1size = argV1.size();
613 auto argV2size = argV2.size();
614 for(int i=0; i<argV1size; ++i)
615 argV1(i)=*arg[i];
616 for(int i=0; i<argV2size; ++i)
617 argV2(i)=*arg[argV1size+i];
618 for(size_t i=0; i<argV1size; ++i)
619 dir1V1(i) = *arg[argV1size+argV2size+i];
620 for(size_t i=0; i<argV2size; ++i)
621 dir1V2(i) = *arg[2*argV1size+argV2size+i];
622 for(size_t i=0; i<argV1size; ++i)
623 dir2V1(i) = *arg[2*argV1size+2*argV2size+i];
624 for(size_t i=0; i<argV2size; ++i)
625 dir2V2(i) = *arg[3*argV1size+2*argV2size+i];
626 return func->dirDer1DirDer1(dir1V1, dir2V1, argV1, argV2) +
627 func->dirDer2DirDer1(dir2V2, dir1V1, argV1, argV2) +
628 func->dirDer2DirDer1(dir1V2, dir2V1, argV1, argV2) +
629 func->dirDer2DirDer2(dir1V2, dir2V2, argV1, argV2);
630 }
631 private:
639};
640
641// ***** Function *****
642
644class FMATVEC_EXPORT NativeFunction : public Vertex, public std::enable_shared_from_this<NativeFunction> {
645 public:
646 static SymbolicExpression create(const std::shared_ptr<ScalarFunctionWrapArg> &funcWrapper,
647 const std::vector<SymbolicExpression> &argS,
648 const std::vector<SymbolicExpression> &dir1S={},
649 const std::vector<SymbolicExpression> &dir2S={});
650 SymbolicExpression parDer(const IndependentVariable &x) const override;
651
652 std::vector<ByteCode>::iterator dumpByteCode(std::vector<ByteCode> &byteCode,
653 std::map<const Vertex*,
654 std::vector<AST::ByteCode>::iterator> &existingVertex) const override;
655
656 void walkVertex(const std::function<void(const std::shared_ptr<const Vertex>&)> &func) const override;
657
658 private:
660 const std::vector<SymbolicExpression> &argS,
661 const std::vector<SymbolicExpression> &dir1S,
662 const std::vector<SymbolicExpression> &dir2S);
663 bool equal(const SymbolicExpression &b, MapIVSE &m) const override;
664
666 const std::vector<SymbolicExpression> argS;
667 const std::vector<SymbolicExpression> dir1S;
668 const std::vector<SymbolicExpression> dir2S;
669
670 using CacheKey = std::tuple<std::weak_ptr<ScalarFunctionWrapArg>,
671 std::vector<std::weak_ptr<const Vertex>>,
672 std::vector<std::weak_ptr<const Vertex>>,
673 std::vector<std::weak_ptr<const Vertex>> >;
675 bool operator()(const CacheKey& l, const CacheKey& r) const;
676 private:
677 std::owner_less<std::weak_ptr<const Vertex>> ol;
678 std::owner_less<std::weak_ptr<const ScalarFunctionWrapArg>> olf;
679 };
680 static std::map<CacheKey, std::weak_ptr<const NativeFunction>, CacheKeyComp> cache;
681};
682
683// ***** Operation *****
684
686class FMATVEC_EXPORT Operation : public Vertex, public std::enable_shared_from_this<Operation> {
687 friend SymbolicExpression;
688 friend SymbolicExpression fmatvec::AST::substScalar(const SymbolicExpression &se,
689 const IndependentVariable& a, const SymbolicExpression &b);
690 friend boost::spirit::qi::rule<boost::spirit::istream_iterator, SymbolicExpression()>&
691 fmatvec::getBoostSpiritQiRule<SymbolicExpression>();
692 friend boost::spirit::karma::rule<std::ostream_iterator<char>, SymbolicExpression()>&
693 fmatvec::getBoostSpiritKarmaRule<SymbolicExpression>();
694 public:
695
697 enum Operator { Plus, Minus, Mult, Div, Pow, Log, Sqrt, Neg, Sin, Cos, Tan, Sinh, Cosh, Tanh, ASin, ACos, ATan, ATan2, ASinh, ACosh, ATanh, Exp, Sign, Heaviside, Abs, Min, Max, Condition };
698 static SymbolicExpression create(Operator op_, const std::vector<SymbolicExpression> &child_);
699 SymbolicExpression parDer(const IndependentVariable &x) const override;
700
701 Operator getOp() const { return op; }
702 const std::vector<SymbolicExpression>& getChilds() const { return child; }
703 std::vector<ByteCode>::iterator dumpByteCode(std::vector<ByteCode> &byteCode,
704 std::map<const Vertex*, std::vector<AST::ByteCode>::iterator> &existingVertex) const override;
705
706 void walkVertex(const std::function<void(const std::shared_ptr<const Vertex>&)> &func) const override;
707
708 private:
709
710 Operation(Operator op_, const std::vector<SymbolicExpression> &child_);
711 bool equal(const SymbolicExpression &b, MapIVSE &m) const override;
712 Operator op;
713 std::vector<SymbolicExpression> child;
714 using CacheKey = std::pair<Operator, std::vector<std::weak_ptr<const Vertex>>>;
716 bool operator()(const CacheKey& l, const CacheKey& r) const;
717 private:
718 std::owner_less<std::weak_ptr<const Vertex>> ol;
719 };
720 static std::map<CacheKey, std::weak_ptr<const Operation>, CacheKeyComp> cache;
721
722 struct OpMap {
723 std::string funcName; // used to dump/read the expression using boost spirit/karma: e.g.
724 // "plus"
725 std::function<void(double*, const ByteCode::Arg&)> func; // used for runtime evaluation: e.g.
726 // [](double* r, const ByteCode::Arg& a){ *r = *a[0] + *a[1]; }
727 };
728 static const std::map<Operator, OpMap> opMap;
729};
730
732 const std::shared_ptr<fmatvec::Function<double(double)>> &func,
733 const SymbolicExpression &arg) {
734 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgS>(func), std::vector<SymbolicExpression>{arg});
735}
736
737template<class Type>
738SymbolicExpression SymbolicFuncWrapArg1<double(Vector<Type, double>), Vector<Type, SymbolicExpression>>::call(
739 const std::shared_ptr<Function<double(Vector<Type, double>)>> &func,
740 const Vector<Type, SymbolicExpression> &arg) {
741 std::vector<SymbolicExpression> argV(arg.size());
742 for(int i=0; i<arg.size(); ++i)
743 argV[i]=arg(i);
744 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgV<Type>>(func, arg.size()), argV);
745}
746
747inline SymbolicExpression SymbolicFuncWrapArg2<double(double,double), SymbolicExpression, SymbolicExpression>::call(
748 const std::shared_ptr<fmatvec::Function<double(double,double)>> &func,
749 const SymbolicExpression &arg1, const SymbolicExpression &arg2) {
750 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgSS>(func), std::vector<SymbolicExpression>{arg1,arg2});
751}
752
753template<class Type>
754SymbolicExpression SymbolicFuncWrapArg2<double(Vector<Type,double>,double), Vector<Type, SymbolicExpression>, SymbolicExpression>::call(
755 const std::shared_ptr<Function<double(Vector<Type,double>,double)>> &func,
756 const Vector<Type, SymbolicExpression> &arg1, const SymbolicExpression &arg2) {
757 std::vector<SymbolicExpression> arg(arg1.size()+1);
758 for(int i=0; i<arg1.size(); ++i)
759 arg[i]=arg1(i);
760 arg[arg1.size()]=arg2;
761 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgVS<Type>>(func, arg1.size()), arg);
762}
763
764template<class Type>
765SymbolicExpression SymbolicFuncWrapArg2<double(double,Vector<Type,double>), SymbolicExpression, Vector<Type, SymbolicExpression>>::call(
766 const std::shared_ptr<Function<double(double,Vector<Type,double>)>> &func,
767 const SymbolicExpression &arg1, const Vector<Type, SymbolicExpression> &arg2) {
768 std::vector<SymbolicExpression> arg(1+arg2.size());
769 arg[0]=arg1;
770 for(int i=0; i<arg2.size(); ++i)
771 arg[i+1]=arg2(i);
772 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgSV<Type>>(func, arg2.size()), arg);
773}
774
775template<class Type1, class Type2>
776SymbolicExpression SymbolicFuncWrapArg2<double(Vector<Type1,double>,Vector<Type2,double>), Vector<Type1, SymbolicExpression>, Vector<Type2, SymbolicExpression>>::call(
777 const std::shared_ptr<Function<double(Vector<Type1,double>,Vector<Type2,double>)>> &func,
778 const Vector<Type1, SymbolicExpression> &arg1, const Vector<Type2, SymbolicExpression> &arg2) {
779 std::vector<SymbolicExpression> arg(arg1.size()+arg2.size());
780 for(int i=0; i<arg1.size(); ++i)
781 arg[i]=arg1(i);
782 for(int i=0; i<arg2.size(); ++i)
783 arg[arg1.size()+i]=arg2(i);
784 return AST::NativeFunction::create(std::make_shared<AST::ScalarFunctionWrapArgVV<Type1,Type2>>(func, arg1.size(), arg2.size()), arg);
785}
786
787} // end namespace AST
788#endif
789
790inline bool operator<(const fmatvec::SymbolicExpression& a, const fmatvec::SymbolicExpression& b) noexcept {
791 // See LessIV why we need to overload this operator< and call abort!
792 std::cerr<<"ABORT: See LessIV: have you called std::min/max instead of fmatvev::min/max with type SymbolicExpression?"<<std::endl;
793 assert(((void)"See LessIV: have you called std::min/max instead of fmatvev::min/max with type SymbolicExpression?", false));
794 abort();
795}
796
798 static_cast<const AST::Symbol*>(get())->setValue(x);
799 return *this;
800}
801
802template<> boost::spirit::qi::rule<boost::spirit::istream_iterator, IndependentVariable()>& getBoostSpiritQiRule<IndependentVariable>();
803template<> boost::spirit::qi::rule<boost::spirit::istream_iterator, SymbolicExpression()>& getBoostSpiritQiRule<SymbolicExpression>();
804
805template<> boost::spirit::karma::rule<std::ostream_iterator<char>, IndependentVariable()>& getBoostSpiritKarmaRule<IndependentVariable>();
806template<> boost::spirit::karma::rule<std::ostream_iterator<char>, SymbolicExpression()>& getBoostSpiritKarmaRule<SymbolicExpression>();
807
808// for vectors/matrices of type IndependentVariable/SymbolicExpression throw exceptions instead of assert.
809// these exceptions are thrown regardless whether NDEBUG is defined or not.
810// this is done since vectors/matrix operations of this type are usually user input, should not abort/assert on errors,
811// and it not time critical since it just build the expression once which is than evaluated at runtime.
812template<> struct AssertUseException<IndependentVariable> { constexpr static bool value = true; };
813template<> struct AssertUseException<SymbolicExpression> { constexpr static bool value = true; };
814
815FMATVEC_MSVC_DISABLEW4251_END
816} // end namespace fmatvec
817
818#endif
A vertex of the AST representing a constant (long or double)
Definition: ast.h:335
bool isConstantInt() const override
Rreturn true if this Vertex is a constant integer.
const T & getValue() const
Get the constant value of the vertex.
Definition: ast.h:369
A vertex of the AST representing an arbitary function.
Definition: ast.h:644
A vertex of the AST representing an operation.
Definition: ast.h:686
Operator
Defined operations.
Definition: ast.h:697
A vertex of the AST representing a independent variable.
Definition: ast.h:376
void setValue(double x_) const
Definition: ast.h:404
A abstract class for a Vertex of the AST (abstract syntax tree).
Definition: ast.h:283
virtual SymbolicExpression parDer(const IndependentVariable &x) const =0
Generate a new AST being the partial derivate of this AST with respect to the variable x.
virtual bool isConstantInt() const
Rreturn true if this Vertex is a constant integer.
Definition: ast.h:327
Definition: symbolic.h:160
Definition: function.h:202
Definition: ast.h:108
IndependentVariable(const std::string &str)
Creates a IndependentVariable variable from the specified string (the string is a serialized Independ...
friend FMATVEC_EXPORT std::istream & operator>>(std::istream &s, IndependentVariable &v)
Create/initialize a IndependentVariable from a stream using deserialization.
IndependentVariable & operator^=(double x)
Set the double value of the independent value.
Definition: ast.h:797
Definition: ast.h:38
SymbolicExpression(const std::string &str)
Creates a expression form the specified string (the string must be a serialized SymbolicExpression).
Definition: matrix.h:167
Definition: types.h:85
Namespace fmatvec.
Definition: _memory.cc:28
SymbolicExpression parDer(const SymbolicExpression &dep, const IndependentVariable &indep)
Definition: ast.cc:299
ostream & operator<<(ostream &s, const SymbolicExpression &se)
Write a SymbolicExpression to a stream using serialization.
Definition: ast.cc:190
Definition: ast.h:209
Definition: ast.h:722
Definition: ast.h:318
Definition: types.h:231