serialize-cereal.h
1 #ifndef SYMENGINE_SERIALIZE_CEREAL_H
2 #define SYMENGINE_SERIALIZE_CEREAL_H
3 #include <symengine/basic.h>
4 #include <symengine/number.h>
5 #include <symengine/integer.h>
6 #include <symengine/symbol.h>
7 #include <symengine/visitor.h>
8 #include <symengine/utilities/stream_fmt.h>
9 
10 #include <cereal/cereal.hpp>
11 #include <cereal/version.hpp>
12 #include <cereal/types/polymorphic.hpp>
13 #include <cereal/types/string.hpp>
14 #include <cereal/details/helpers.hpp>
15 #include <cereal/types/map.hpp>
16 #include <cereal/types/unordered_map.hpp>
17 #include <cereal/types/set.hpp>
18 #include <cereal/types/vector.hpp>
19 #include <cereal/types/utility.hpp>
20 #include <cereal/archives/portable_binary.hpp>
21 
22 namespace SymEngine
23 {
24 
25 template <class Archive>
26 inline void save_basic(Archive &ar, const Basic &b)
27 {
28  const auto t_code = b.get_type_code();
29  throw SerializationError(StreamFmt()
30  << __FILE__ << ":" << __LINE__
31 #ifndef _MSC_VER
32  << ": " << __PRETTY_FUNCTION__
33 #endif
34  << " not supported: " << type_code_name(t_code)
35  << " (" << t_code << ")"
36 #if !defined(NDEBUG)
37  << ", " << b.__str__()
38 #endif
39  );
40 }
41 template <class Archive>
42 inline void save_basic(Archive &ar, const Symbol &b)
43 {
44  ar(b.__str__());
45 }
46 template <class Archive>
47 inline void save_basic(Archive &ar, const Mul &b)
48 {
49  ar(b.get_coef());
50  ar(b.get_dict());
51 }
52 template <class Archive>
53 inline void save_basic(Archive &ar, const Add &b)
54 {
55  ar(b.get_coef());
56  ar(b.get_dict());
57 }
58 template <class Archive>
59 inline void save_basic(Archive &ar, const Pow &b)
60 {
61  ar(b.get_base());
62  ar(b.get_exp());
63 }
64 template <typename Archive>
65 void save_helper(Archive &ar, const integer_class &intgr)
66 {
68  s << intgr; // stream to string
69  ar(s.str());
70 }
71 template <typename Archive>
72 void save_helper(Archive &ar, const rational_class &rat)
73 {
74  integer_class num = get_num(rat);
75  integer_class den = get_den(rat);
76  save_helper(ar, num);
77  save_helper(ar, den);
78 }
79 // Following is an ugly hack for templated integer classes
80 // Not sure why a direct version doesn't work
81 template <typename Archive>
82 void save_basic(Archive &ar, const URatPoly &b)
83 {
84  ar(b.get_var());
85  const URatDict &urd = b.get_poly();
86  size_t l = urd.size();
87  ar(l);
88  for (auto &p : urd.dict_) {
89  unsigned int first = p.first;
90  const rational_class &second = p.second;
91  ar(first);
92  save_helper(ar, second);
93  }
94 }
95 template <class Archive>
96 inline void save_basic(Archive &ar, const Integer &b)
97 {
98  ar(b.__str__());
99 }
100 template <class Archive>
101 inline void save_basic(Archive &ar, const RealDouble &b)
102 {
103  ar(b.i);
104 }
105 template <class Archive>
106 inline void save_basic(Archive &ar, const Rational &b)
107 {
108  ar(b.get_num(), b.get_den());
109 }
110 template <class Archive>
111 inline void save_basic(Archive &ar, const ComplexBase &b)
112 {
113  ar(b.real_part(), b.imaginary_part());
114 }
115 template <class Archive>
116 inline void save_basic(Archive &ar, const Interval &b)
117 {
118  ar(b.get_left_open(), b.get_start(), b.get_right_open(), b.get_end());
119 }
120 template <class Archive>
121 inline void save_basic(Archive &ar, const BooleanAtom &b)
122 {
123  ar(b.get_val());
124 }
125 template <class Archive>
126 inline void save_basic(Archive &ar, const Infty &b)
127 {
128  ar(b.get_direction());
129 }
130 
131 template <class Archive>
132 inline void save_basic(Archive &ar, const NaN &b)
133 {
134 }
135 
136 template <class Archive>
137 inline void save_basic(Archive &ar, const Constant &b)
138 {
139  ar(b.get_name());
140 }
141 template <class Archive>
142 inline void save_basic(Archive &ar, const OneArgFunction &b)
143 {
144  ar(b.get_arg());
145 }
146 template <class Archive>
147 inline void save_basic(Archive &ar, const TwoArgFunction &b)
148 {
149  ar(b.get_arg1(), b.get_arg2());
150 }
151 
152 template <class Archive>
153 inline void save_basic(Archive &ar, const Relational &b)
154 {
155  ar(b.get_arg1(), b.get_arg2());
156 }
157 template <class Archive>
158 inline void save_basic(Archive &ar, const And &b)
159 {
160  ar(b.get_container());
161 }
162 template <class Archive>
163 inline void save_basic(Archive &ar, const Or &b)
164 {
165  ar(b.get_container());
166 }
167 template <class Archive>
168 inline void save_basic(Archive &ar, const Xor &b)
169 {
170  ar(b.get_container());
171 }
172 template <class Archive>
173 inline void save_basic(Archive &ar, const Not &b)
174 {
175  ar(b.get_arg());
176 }
177 template <class Archive>
178 inline void save_basic(Archive &ar, const Contains &b)
179 {
180  ar(b.get_expr(), b.get_set());
181 }
182 template <class Archive>
183 inline void save_basic(Archive &ar, const Piecewise &b)
184 {
185  ar(b.get_vec());
186 }
187 template <class Archive>
188 inline void save_basic(Archive &ar, const Reals &b)
189 {
190 }
191 template <class Archive>
192 inline void save_basic(Archive &ar, const Rationals &b)
193 {
194 }
195 template <class Archive>
196 inline void save_basic(Archive &ar, const EmptySet &b)
197 {
198 }
199 template <class Archive>
200 inline void save_basic(Archive &ar, const Integers &b)
201 {
202 }
203 template <class Archive>
204 inline void save_basic(Archive &ar, const UniversalSet &b)
205 {
206 }
207 template <class Archive>
208 inline void save_basic(Archive &ar, const Union &b)
209 {
210  ar(b.get_container());
211 }
212 template <class Archive>
213 inline void save_basic(Archive &ar, const Complement &b)
214 {
215  ar(b.get_universe(), b.get_container());
216 }
217 template <class Archive>
218 inline void save_basic(Archive &ar, const ImageSet &b)
219 {
220  ar(b.get_symbol(), b.get_expr(), b.get_baseset());
221 }
222 template <class Archive>
223 inline void save_basic(Archive &ar, const FiniteSet &b)
224 {
225  ar(b.get_container());
226 }
227 template <class Archive>
228 inline void save_basic(Archive &ar, const ConditionSet &b)
229 {
230  ar(b.get_symbol(), b.get_condition());
231 }
232 #ifdef HAVE_SYMENGINE_MPFR
233 template <class Archive>
234 inline void save_basic(Archive &ar, const RealMPFR &b)
235 {
236  ar(b.__str__(), b.get_prec());
237 }
238 #endif
239 template <class Archive>
240 inline void save_basic(Archive &ar, const GaloisField &b)
241 {
242  throw NotImplementedError("GaloisField saving is not implemented yet.");
243 }
244 template <class Archive>
245 inline void save_basic(Archive &ar, const SeriesCoeffInterface &)
246 {
247  throw NotImplementedError("Series saving is not implemented yet.");
248 }
249 template <class Archive>
250 inline void save_basic(Archive &ar, const MultiArgFunction &b)
251 {
252  ar(b.get_args());
253 }
254 template <class Archive>
255 inline void save_basic(Archive &ar, const FunctionSymbol &b)
256 {
257  ar(b.get_name(), b.get_args());
258 }
259 template <class Archive>
260 inline void save_basic(Archive &ar, const Derivative &b)
261 {
262  ar(b.get_arg(), b.get_symbols());
263 }
264 template <class Archive>
265 inline void save_basic(Archive &ar, const Subs &b)
266 {
267  ar(b.get_arg(), b.get_dict());
268 }
269 template <class Archive>
270 inline void save_basic(Archive &ar, const NumberWrapper &b)
271 {
272  throw NotImplementedError("NumberWrapper saving is not implemented yet.");
273 }
274 template <class Archive>
275 inline void save_basic(Archive &ar, const FunctionWrapper &b)
276 {
277  throw NotImplementedError("FunctionWrapper saving is not implemented yet.");
278 }
279 
280 template <class Archive>
281 inline void save_basic(Archive &ar, RCP<const Basic> const &ptr)
282 {
283 #if CEREAL_VERSION >= 10301
284  std::shared_ptr<void> sharedPtr = std::static_pointer_cast<void>(
285  std::make_shared<RCP<const Basic>>(ptr));
286  uint32_t id = ar.registerSharedPointer(sharedPtr);
287 #else
288  uint32_t id = ar.registerSharedPointer(ptr.get());
289 #endif
290  ar(CEREAL_NVP(id));
291 
292  if (id & cereal::detail::msb_32bit) {
293  ar(ptr->get_type_code());
294  switch (ptr->get_type_code()) {
295 #define SYMENGINE_ENUM(type, Class) \
296  case type: \
297  save_basic(ar, static_cast<const Class &>(*ptr)); \
298  break;
299 #include "symengine/type_codes.inc"
300 #undef SYMENGINE_ENUM
301  default:
302  save_basic(ar, *ptr);
303  }
304  }
305 }
306 
308 template <class Archive, class T>
309 inline void CEREAL_SAVE_FUNCTION_NAME(Archive &ar, RCP<const T> const &ptr)
310 {
311  save_basic(ar, rcp_static_cast<const Basic>(ptr));
312 }
313 template <class Archive>
314 RCP<const Basic> load_basic(Archive &ar, RCP<const RealDouble> &)
315 {
316  double val;
317  ar(val);
318  return real_double(val);
319 }
320 template <class Archive>
321 RCP<const Basic> load_basic(Archive &ar, RCP<const Infty> &)
322 {
323  RCP<const Number> direction;
324  ar(direction);
325  return Infty::from_direction(direction);
326 }
327 template <class Archive>
328 RCP<const Basic> load_basic(Archive &ar, RCP<const NaN> &)
329 {
330  return rcp_static_cast<const Basic>(Nan);
331 }
332 template <class Archive>
333 RCP<const Basic> load_basic(Archive &ar, RCP<const Symbol> &)
334 {
335  std::string name;
336  ar(name);
337  return symbol(name);
338 }
339 template <class Archive>
340 RCP<const Basic> load_basic(Archive &ar, RCP<const Mul> &)
341 {
342  RCP<const Number> coeff;
343  map_basic_basic dict;
344  ar(coeff);
345  ar(dict);
346  return make_rcp<const Mul>(coeff, std::move(dict));
347 }
348 template <class Archive>
349 RCP<const Basic> load_basic(Archive &ar, RCP<const Add> &)
350 {
351  RCP<const Number> coeff;
352  umap_basic_num dict;
353  ar(coeff);
354  ar(dict);
355  return make_rcp<const Add>(coeff, std::move(dict));
356 }
357 template <class Archive>
358 RCP<const Basic> load_basic(Archive &ar, RCP<const Pow> &)
359 {
360  RCP<const Basic> base, exp;
361  ar(base);
362  ar(exp);
363  return make_rcp<const Pow>(base, exp);
364 }
365 template <typename Archive>
366 void load_helper(Archive &ar, integer_class &intgr)
367 {
368  std::string int_str;
369  ar(int_str);
370  intgr = integer_class(std::move(int_str));
371 }
372 template <typename Archive>
373 void load_helper(Archive &ar, const rational_class &rat)
374 {
375  integer_class num, den;
376  load_helper(ar, num);
377  load_helper(ar, den);
378 }
379 // Following is an ugly hack for templated integer classes
380 // Not sure why the other clean version doesn't work
381 template <typename Archive>
382 RCP<const Basic> load_basic(Archive &ar, const URatPoly &b)
383 {
384  RCP<const Basic> var;
385  size_t l;
386  ar(var);
387  ar(l);
389  auto hint = d.begin();
390  for (size_t i = 0; i < l; i++) {
391  unsigned int first;
392  rational_class second;
393  ar(first);
394  load_helper(ar, second);
395 #if !defined(__clang__) && (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
396  d.insert(hint, std::make_pair(std::move(first), std::move(second)));
397 #else
398  d.emplace_hint(hint, std::move(first), std::move(second));
399 #endif
400  }
401  return make_rcp<const URatPoly>(var, URatDict(std::move(d)));
402 }
403 template <class Archive>
404 RCP<const Basic> load_basic(Archive &ar, RCP<const Integer> &)
405 {
406  std::string int_str;
407  ar(int_str);
408  return integer(integer_class(int_str));
409 }
410 template <class Archive>
411 RCP<const Basic> load_basic(Archive &ar, RCP<const Constant> &)
412 {
413  std::string name;
414  ar(name);
415  return constant(name);
416 }
417 template <class Archive>
418 RCP<const Basic> load_basic(Archive &ar, RCP<const Rational> &)
419 {
420  RCP<const Integer> num, den;
421  ar(num, den);
422  return Rational::from_two_ints(*num, *den);
423 }
424 template <class Archive>
425 RCP<const Basic> load_basic(Archive &ar, RCP<const Complex> &)
426 {
427  RCP<const Number> num, den;
428  ar(num, den);
429  return Complex::from_two_nums(*num, *den);
430 }
431 template <class Archive, class T>
432 RCP<const Basic>
433 load_basic(Archive &ar, RCP<const T> &,
435  int>::type * = nullptr)
436 {
437  RCP<const Number> num, den;
438  ar(num, den);
439  return addnum(num, mulnum(I, den));
440 }
441 template <class Archive>
442 RCP<const Basic> load_basic(Archive &ar, RCP<const Interval> &)
443 {
444  RCP<const Number> start, end;
445  bool left_open, right_open;
446  ar(left_open, start, right_open, end);
447  return make_rcp<const Interval>(start, end, left_open, right_open);
448 }
449 template <class Archive>
450 RCP<const Basic> load_basic(Archive &ar, RCP<const BooleanAtom> &)
451 {
452  bool val;
453  ar(val);
454  return boolean(val);
455 }
456 template <class Archive>
457 RCP<const Basic> load_basic(Archive &ar, RCP<const And> &)
458 {
459  set_boolean container;
460  ar(container);
461  return make_rcp<const And>(std::move(container));
462 }
463 template <class Archive>
464 RCP<const Basic> load_basic(Archive &ar, RCP<const Or> &)
465 {
466  set_boolean container;
467  ar(container);
468  return make_rcp<const Or>(std::move(container));
469 }
470 template <class Archive>
471 RCP<const Basic> load_basic(Archive &ar, RCP<const Xor> &)
472 {
473  vec_boolean container;
474  ar(container);
475  return make_rcp<const Xor>(std::move(container));
476 }
477 template <class Archive>
478 RCP<const Basic> load_basic(Archive &ar, RCP<const Not> &)
479 {
480  RCP<const Boolean> arg;
481  ar(arg);
482  return make_rcp<const Not>(arg);
483 }
484 template <class Archive>
485 RCP<const Basic> load_basic(Archive &ar, RCP<const Piecewise> &)
486 {
487  PiecewiseVec vec;
488  ar(vec);
489  return make_rcp<const Piecewise>(std::move(vec));
490 }
491 template <class Archive>
492 RCP<const Basic> load_basic(Archive &ar, RCP<const Contains> &)
493 {
494  RCP<const Basic> expr;
495  RCP<const Set> contains_set;
496  ar(expr, contains_set);
497  return make_rcp<const Contains>(expr, contains_set);
498 }
499 template <class Archive>
500 RCP<const Basic> load_basic(Archive &ar, RCP<const Reals> &)
501 {
502  return reals();
503 }
504 template <class Archive>
505 RCP<const Basic> load_basic(Archive &ar, RCP<const Rationals> &)
506 {
507  return rationals();
508 }
509 template <class Archive>
510 RCP<const Basic> load_basic(Archive &ar, RCP<const EmptySet> &)
511 {
512  return emptyset();
513 }
514 template <class Archive>
515 RCP<const Basic> load_basic(Archive &ar, RCP<const Integers> &)
516 {
517  return integers();
518 }
519 template <class Archive>
520 RCP<const Basic> load_basic(Archive &ar, RCP<const UniversalSet> &)
521 {
522  return universalset();
523 }
524 template <class Archive>
525 RCP<const Basic> load_basic(Archive &ar, RCP<const Union> &)
526 {
527  set_set union_set;
528  ar(union_set);
529  return make_rcp<const Union>(std::move(union_set));
530 }
531 template <class Archive>
532 RCP<const Basic> load_basic(Archive &ar, RCP<const Complement> &)
533 {
534  RCP<const Set> universe, container;
535  ar(universe, container);
536  return make_rcp<const Complement>(universe, container);
537 }
538 template <class Archive>
539 RCP<const Basic> load_basic(Archive &ar, RCP<const ImageSet> &)
540 {
541  RCP<const Basic> sym, expr;
542  RCP<const Set> base;
543  ar(sym, expr, base);
544  return make_rcp<const ImageSet>(sym, expr, base);
545 }
546 template <class Archive>
547 RCP<const Basic> load_basic(Archive &ar, RCP<const FiniteSet> &)
548 {
549  set_basic set;
550  ar(set);
551  return make_rcp<const FiniteSet>(set);
552 }
553 template <class Archive>
554 RCP<const Basic> load_basic(Archive &ar, RCP<const ConditionSet> &)
555 {
556  RCP<const Basic> sym;
557  RCP<const Boolean> condition;
558  ar(sym, condition);
559  return make_rcp<const ConditionSet>(sym, condition);
560 }
561 #ifdef HAVE_SYMENGINE_MPFR
562 template <class Archive>
563 RCP<const Basic> load_basic(Archive &ar, RCP<const RealMPFR> &)
564 {
565  std::string num;
566  unsigned prec;
567  ar(num, prec);
568  return make_rcp<const RealMPFR>(mpfr_class(num, prec, 10));
569 }
570 #endif
571 template <class Archive>
572 RCP<const Basic> load_basic(Archive &ar, RCP<const Derivative> &)
573 {
574  RCP<const Basic> arg;
575  multiset_basic set;
576  ar(arg, set);
577  return make_rcp<const Derivative>(arg, std::move(set));
578 }
579 template <class Archive>
580 RCP<const Basic> load_basic(Archive &ar, RCP<const Subs> &)
581 {
582  RCP<const Basic> arg;
583  map_basic_basic dict;
584  ar(arg, dict);
585  return make_rcp<const Subs>(arg, std::move(dict));
586 }
587 
588 template <class Archive, class T>
589 RCP<const Basic>
590 load_basic(Archive &ar, RCP<const T> &,
592  int>::type * = nullptr)
593 {
594  RCP<const Basic> arg;
595  ar(arg);
596  return make_rcp<const T>(arg);
597 }
598 template <class Archive, class T>
599 RCP<const Basic>
600 load_basic(Archive &ar, RCP<const T> &,
602  int>::type * = nullptr)
603 {
604  RCP<const Basic> arg1, arg2;
605  ar(arg1, arg2);
606  return make_rcp<const T>(arg1, arg2);
607 }
608 template <class Archive>
609 RCP<const Basic> load_basic(Archive &ar, RCP<const FunctionSymbol> &)
610 {
611  std::string name;
612  vec_basic vec;
613  ar(name, vec);
614  return make_rcp<const FunctionSymbol>(name, std::move(vec));
615 }
616 template <class Archive>
617 RCP<const Basic> load_basic(Archive &ar, RCP<const FunctionWrapper> &)
618 {
619  throw SerializationError(StreamFmt()
620  << __FILE__ << ":" << __LINE__
621 #ifndef _MSC_VER
622  << ": " << __PRETTY_FUNCTION__
623 #endif
624  << "Loading of this type is not implemented.");
625 }
626 template <class Archive, class T>
627 RCP<const Basic>
628 load_basic(Archive &ar, RCP<const T> &,
630  int>::type * = nullptr)
631 {
632  vec_basic args;
633  ar(args);
634  return make_rcp<const T>(std::move(args));
635 }
636 template <class Archive, class T>
637 RCP<const Basic>
638 load_basic(Archive &ar, RCP<const T> &,
640  int>::type * = nullptr)
641 {
642  RCP<const Basic> arg1, arg2;
643  ar(arg1, arg2);
644  return make_rcp<const T>(arg1, arg2);
645 }
646 template <class Archive, class T>
647 RCP<const Basic> load_basic(
648  Archive &ar, RCP<const T> &,
654  int>::type * = nullptr)
655 {
656  throw SerializationError(StreamFmt()
657  << __FILE__ << ":" << __LINE__
658 #ifndef _MSC_VER
659  << ": " << __PRETTY_FUNCTION__
660 #endif
661  << "Loading of this type is not implemented.");
662 }
663 
665 template <class Archive, class T>
666 inline void CEREAL_LOAD_FUNCTION_NAME(Archive &ar, RCP<const T> &ptr)
667 {
668  uint32_t id;
669  ar(CEREAL_NVP(id));
670 
671  if (id & cereal::detail::msb_32bit) {
672  TypeID type_code;
673  ar(type_code);
674  switch (type_code) {
675 #define SYMENGINE_ENUM(type_enum, Class) \
676  case type_enum: { \
677  if (not std::is_base_of<T, Class>::value) { \
678  throw std::runtime_error("Cannot convert to type."); \
679  } else { \
680  RCP<const Class> dummy_ptr; \
681  ptr = rcp_static_cast<const T>( \
682  rcp_static_cast<const Basic>(load_basic(ar, dummy_ptr))); \
683  break; \
684  } \
685  }
686 #include "symengine/type_codes.inc"
687 #undef SYMENGINE_ENUM
688  default:
689  throw std::runtime_error("Unknown type");
690  }
691  std::shared_ptr<void> sharedPtr = std::static_pointer_cast<void>(
692  std::make_shared<RCP<const Basic>>(ptr));
693 
694  ar.registerSharedPointer(id, sharedPtr);
695  } else {
697  = std::static_pointer_cast<RCP<const T>>(ar.getSharedPointer(id));
698  ptr = *sharedPtr.get();
699  }
700 }
701 } // namespace SymEngine
702 #endif // SYMENGINE_SERIALIZE_CEREAL_H
The base class for SymEngine.
T begin(T... args)
static RCP< const Number > from_two_nums(const Number &re, const Number &im)
Definition: complex.cpp:109
static RCP< const Number > from_two_ints(const Integer &n, const Integer &d)
Definition: rational.cpp:44
T emplace_hint(T... args)
T end(T... args)
T get(T... args)
T insert(T... args)
T make_pair(T... args)
T make_shared(T... args)
T move(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:197
RCP< const Symbol > symbol(const std::string &name)
inline version to return Symbol
Definition: symbol.h:82
RCP< const Number > mulnum(const RCP< const Number > &self, const RCP< const Number > &other)
Multiply self and other
Definition: number.h:93
RCP< const Reals > reals()
Definition: sets.h:560
RCP< const EmptySet > emptyset()
Definition: sets.h:590
RCP< const Integers > integers()
Definition: sets.h:572
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:271
RCP< const UniversalSet > universalset()
Definition: sets.h:596
TypeID
Definition: basic.h:43
RCP< const Constant > constant(const std::string &name)
inline version to return Constant
Definition: constants.h:53
void CEREAL_SAVE_FUNCTION_NAME(Archive &ar, RCP< const T > const &ptr)
Saving for SymEngine::RCP.
void CEREAL_LOAD_FUNCTION_NAME(Archive &ar, RCP< const T > &ptr)
Loading for SymEngine::RCP.
RCP< const Rationals > rationals()
Definition: sets.h:566
RCP< const Number > addnum(const RCP< const Number > &self, const RCP< const Number > &other)
Add self and other
Definition: number.h:81
T str(T... args)