strprinter.cpp
1 #include <limits>
2 #include <symengine/printers/strprinter.h>
3 
4 namespace SymEngine
5 {
6 
10  bool operator()(const RCP<const Basic> &x, const RCP<const Basic> &y) const
11  {
12  if (x->__eq__(*y))
13  return false;
14  return x->__cmp__(*y) == -1;
15  }
16 };
17 
18 std::string ascii_art()
19 {
20  std::string a = " _____ _____ _ \n"
21  "| __|_ _ _____| __|___ ___|_|___ ___ \n"
22  "|__ | | | | __| | . | | | -_|\n"
23  "|_____|_ |_|_|_|_____|_|_|_ |_|_|_|___|\n"
24  " |___| |___| \n";
25  return a;
26 }
27 
28 void Precedence::bvisit(const Add &x)
29 {
30  precedence = PrecedenceEnum::Add;
31 }
32 
33 void Precedence::bvisit(const Mul &x)
34 {
35  precedence = PrecedenceEnum::Mul;
36 }
37 
38 void Precedence::bvisit(const Relational &x)
39 {
40  precedence = PrecedenceEnum::Relational;
41 }
42 
43 void Precedence::bvisit(const Pow &x)
44 {
45  precedence = PrecedenceEnum::Pow;
46 }
47 
48 void Precedence::bvisit(const GaloisField &x)
49 {
50  // iterators need to be implemented
51  // bvisit_upoly(x);
52 }
53 
54 void Precedence::bvisit(const Rational &x)
55 {
56  precedence = PrecedenceEnum::Add;
57 }
58 
59 void Precedence::bvisit(const Complex &x)
60 {
61  if (x.is_re_zero()) {
62  if (x.imaginary_ == 1) {
63  precedence = PrecedenceEnum::Atom;
64  } else {
65  precedence = PrecedenceEnum::Mul;
66  }
67  } else {
68  precedence = PrecedenceEnum::Add;
69  }
70 }
71 
72 void Precedence::bvisit(const Integer &x)
73 {
74  if (x.is_negative()) {
75  precedence = PrecedenceEnum::Mul;
76  } else {
77  precedence = PrecedenceEnum::Atom;
78  }
79 }
80 
81 void Precedence::bvisit(const RealDouble &x)
82 {
83  if (x.is_negative()) {
84  precedence = PrecedenceEnum::Mul;
85  } else {
86  precedence = PrecedenceEnum::Atom;
87  }
88 }
89 
90 #ifdef HAVE_SYMENGINE_PIRANHA
91 void Precedence::bvisit(const URatPSeriesPiranha &x)
92 {
93  precedence = PrecedenceEnum::Add;
94 }
95 
96 void Precedence::bvisit(const UPSeriesPiranha &x)
97 {
98  precedence = PrecedenceEnum::Add;
99 }
100 #endif
101 void Precedence::bvisit(const ComplexDouble &x)
102 {
103  precedence = PrecedenceEnum::Add;
104 }
105 #ifdef HAVE_SYMENGINE_MPFR
106 void Precedence::bvisit(const RealMPFR &x)
107 {
108  if (x.is_negative()) {
109  precedence = PrecedenceEnum::Mul;
110  } else {
111  precedence = PrecedenceEnum::Atom;
112  }
113 }
114 #endif
115 #ifdef HAVE_SYMENGINE_MPC
116 void Precedence::bvisit(const ComplexMPC &x)
117 {
118  precedence = PrecedenceEnum::Add;
119 }
120 #endif
121 
122 void Precedence::bvisit(const Basic &x)
123 {
124  precedence = PrecedenceEnum::Atom;
125 }
126 
127 PrecedenceEnum Precedence::getPrecedence(const RCP<const Basic> &x)
128 {
129  (*x).accept(*this);
130  return precedence;
131 }
132 
133 void StrPrinter::bvisit(const Basic &x)
134 {
136  s << "<" << typeName<Basic>(x) << " instance at " << (const void *)this
137  << ">";
138  str_ = s.str();
139 }
140 
141 void StrPrinter::bvisit(const Symbol &x)
142 {
143  str_ = x.get_name();
144 }
145 
146 void StrPrinter::bvisit(const Infty &x)
147 {
149  if (x.is_negative_infinity())
150  s << "-oo";
151  else if (x.is_positive_infinity())
152  s << "oo";
153  else
154  s << "zoo";
155  str_ = s.str();
156 }
157 
158 void StrPrinter::bvisit(const NaN &x)
159 {
161  s << "nan";
162  str_ = s.str();
163 }
164 
165 void StrPrinter::bvisit(const Integer &x)
166 {
168  s << x.as_integer_class();
169  str_ = s.str();
170 }
171 
172 void StrPrinter::bvisit(const Rational &x)
173 {
175  s << x.as_rational_class();
176  str_ = s.str();
177 }
178 
179 void StrPrinter::bvisit(const Complex &x)
180 {
182  if (x.real_ != 0) {
183  s << x.real_;
184  // Since Complex is in canonical form, imaginary_ is not 0.
185  if (mp_sign(x.imaginary_) == 1) {
186  s << " + ";
187  } else {
188  s << " - ";
189  }
190  // If imaginary_ is not 1 or -1, print the absolute value
191  if (x.imaginary_ != mp_sign(x.imaginary_)) {
192  s << mp_abs(x.imaginary_);
193  s << print_mul() << get_imag_symbol();
194  } else {
195  s << "I";
196  }
197  } else {
198  if (x.imaginary_ != mp_sign(x.imaginary_)) {
199  s << x.imaginary_;
200  s << print_mul() << get_imag_symbol();
201  } else {
202  if (mp_sign(x.imaginary_) == 1) {
203  s << get_imag_symbol();
204  } else {
205  s << "-" << get_imag_symbol();
206  }
207  }
208  }
209  str_ = s.str();
210 }
211 
212 std::string print_double(double d)
213 {
216  s << d;
217  auto str_ = s.str();
218  if (str_.find(".") == std::string::npos
219  and str_.find("e") == std::string::npos) {
220  if (std::numeric_limits<double>::digits10 - str_.size() > 0) {
221  str_ += ".0";
222  } else {
223  str_ += ".";
224  }
225  }
226  return str_;
227 }
228 
229 void StrPrinter::bvisit(const RealDouble &x)
230 {
231  str_ = print_double(x.i);
232 }
233 
234 void StrPrinter::bvisit(const ComplexDouble &x)
235 {
236  str_ = print_double(x.i.real());
237  if (x.i.imag() < 0) {
238  str_ += " - " + print_double(-x.i.imag()) + print_mul()
239  + get_imag_symbol();
240  } else {
241  str_ += " + " + print_double(x.i.imag()) + print_mul()
242  + get_imag_symbol();
243  }
244 }
245 
246 void StrPrinter::bvisit(const Equality &x)
247 {
249  s << apply(x.get_arg1()) << " == " << apply(x.get_arg2());
250  str_ = s.str();
251 }
252 
253 void StrPrinter::bvisit(const Unequality &x)
254 {
256  s << apply(x.get_arg1()) << " != " << apply(x.get_arg2());
257  str_ = s.str();
258 }
259 
260 void StrPrinter::bvisit(const LessThan &x)
261 {
263  s << apply(x.get_arg1()) << " <= " << apply(x.get_arg2());
264  str_ = s.str();
265 }
266 
267 void StrPrinter::bvisit(const StrictLessThan &x)
268 {
270  s << apply(x.get_arg1()) << " < " << apply(x.get_arg2());
271  str_ = s.str();
272 }
273 
274 void StrPrinter::bvisit(const Interval &x)
275 {
277  if (x.get_left_open())
278  s << "(";
279  else
280  s << "[";
281  s << *x.get_start() << ", " << *x.get_end();
282  if (x.get_right_open())
283  s << ")";
284  else
285  s << "]";
286  str_ = s.str();
287 }
288 
289 void StrPrinter::bvisit(const BooleanAtom &x)
290 {
291  if (x.get_val()) {
292  str_ = "True";
293  } else {
294  str_ = "False";
295  }
296 }
297 
298 void StrPrinter::bvisit(const And &x)
299 {
301  auto container = x.get_container();
302  s << "And(";
303  s << apply(*container.begin());
304  for (auto it = ++(container.begin()); it != container.end(); ++it) {
305  s << ", " << apply(*it);
306  }
307  s << ")";
308  str_ = s.str();
309 }
310 
311 void StrPrinter::bvisit(const Or &x)
312 {
314  auto container = x.get_container();
315  s << "Or(";
316  s << apply(*container.begin());
317  for (auto it = ++(container.begin()); it != container.end(); ++it) {
318  s << ", " << apply(*it);
319  }
320  s << ")";
321  str_ = s.str();
322 }
323 
324 void StrPrinter::bvisit(const Xor &x)
325 {
327  auto container = x.get_container();
328  s << "Xor(";
329  s << apply(*container.begin());
330  for (auto it = ++(container.begin()); it != container.end(); ++it) {
331  s << ", " << apply(*it);
332  }
333  s << ")";
334  str_ = s.str();
335 }
336 
337 void StrPrinter::bvisit(const Not &x)
338 {
340  s << "Not(" << *x.get_arg() << ")";
341  str_ = s.str();
342 }
343 
344 void StrPrinter::bvisit(const Contains &x)
345 {
347  s << "Contains(" << apply(x.get_expr()) << ", " << apply(x.get_set())
348  << ")";
349  str_ = s.str();
350 }
351 
352 void StrPrinter::bvisit(const Piecewise &x)
353 {
355  auto vec = x.get_vec();
356  auto it = vec.begin();
357  s << "Piecewise(";
358  while (true) {
359  s << "(";
360  s << apply((*it).first);
361  s << ", ";
362  s << apply((*it).second);
363  s << ")";
364  ++it;
365  if (it != vec.end()) {
366  s << ", ";
367  } else {
368  break;
369  }
370  }
371  s << ")";
372  str_ = s.str();
373 }
374 
375 void StrPrinter::bvisit(const Complexes &x)
376 {
377  str_ = "Complexes";
378 }
379 
380 void StrPrinter::bvisit(const Reals &x)
381 {
382  str_ = "Reals";
383 }
384 
385 void StrPrinter::bvisit(const Rationals &x)
386 {
387  str_ = "Rationals";
388 }
389 
390 void StrPrinter::bvisit(const Integers &x)
391 {
392  str_ = "Integers";
393 }
394 
395 void StrPrinter::bvisit(const EmptySet &x)
396 {
397  str_ = "EmptySet";
398 }
399 
400 void StrPrinter::bvisit(const Union &x)
401 {
403  s << apply(*x.get_container().begin());
404  for (auto it = ++(x.get_container().begin()); it != x.get_container().end();
405  ++it) {
406  s << " U " << apply(*it);
407  }
408  str_ = s.str();
409 }
410 
411 void StrPrinter::bvisit(const Complement &x)
412 {
414  s << apply(*x.get_universe());
415  s << " \\ " << apply(*x.get_container());
416  str_ = s.str();
417 }
418 
419 void StrPrinter::bvisit(const ImageSet &x)
420 {
422  s << "{" << apply(*x.get_expr()) << " | ";
423  s << apply(*x.get_symbol());
424  s << " in " << apply(*x.get_baseset()) << "}";
425  str_ = s.str();
426 }
427 
428 void StrPrinter::bvisit(const UniversalSet &x)
429 {
430  str_ = "UniversalSet";
431 }
432 
433 void StrPrinter::bvisit(const FiniteSet &x)
434 {
436  s << x.get_container();
437  str_ = s.str();
438 }
439 
440 void StrPrinter::bvisit(const ConditionSet &x)
441 {
443  s << "{" << apply(*x.get_symbol());
444  s << " | " << apply(x.get_condition()) << "}";
445  str_ = s.str();
446 }
447 
448 #ifdef HAVE_SYMENGINE_MPFR
449 void StrPrinter::bvisit(const RealMPFR &x)
450 {
451  mpfr_exp_t ex;
452  // mpmath.libmp.libmpf.prec_to_dps
453  long digits
454  = std::max(long(1), std::lround(static_cast<double>(x.i.get_prec())
455  / 3.3219280948873626)
456  - 1);
457  char *c
458  = mpfr_get_str(nullptr, &ex, 10, digits, x.i.get_mpfr_t(), MPFR_RNDN);
460  str_ = std::string(c);
461  if (str_.at(0) == '-') {
462  s << '-';
463  str_ = str_.substr(1, str_.length() - 1);
464  }
465  if (ex > 6) {
466  s << str_.at(0) << '.' << str_.substr(1, str_.length() - 1) << 'e'
467  << (ex - 1);
468  } else if (ex > 0) {
469  s << str_.substr(0, (unsigned long)ex) << ".";
470  s << str_.substr((unsigned long)ex, str_.length() - ex);
471  } else if (ex > -5) {
472  s << "0.";
473  for (int i = 0; i < -ex; ++i) {
474  s << '0';
475  }
476  s << str_;
477  } else {
478  s << str_.at(0) << '.' << str_.substr(1, str_.length() - 1) << 'e'
479  << (ex - 1);
480  }
481  mpfr_free_str(c);
482  str_ = s.str();
483 }
484 #endif
485 #ifdef HAVE_SYMENGINE_MPC
486 void StrPrinter::bvisit(const ComplexMPC &x)
487 {
488  RCP<const Number> imag = x.imaginary_part();
489  if (imag->is_negative()) {
490  std::string str = this->apply(imag);
491  str = str.substr(1, str.length() - 1);
492  str_ = this->apply(x.real_part()) + " - " + str + print_mul()
493  + get_imag_symbol();
494  } else {
495  str_ = this->apply(x.real_part()) + " + " + this->apply(imag)
496  + print_mul() + get_imag_symbol();
497  }
498 }
499 #endif
500 void StrPrinter::bvisit(const Add &x)
501 {
503  bool first = true;
504  std::map<RCP<const Basic>, RCP<const Number>, PrinterBasicCmp> dict(
505  x.get_dict().begin(), x.get_dict().end());
506 
507  if (neq(*(x.get_coef()), *zero)) {
508  o << this->apply(x.get_coef());
509  first = false;
510  }
511  for (const auto &p : dict) {
512  std::string t;
513  if (eq(*(p.second), *one)) {
514  t = parenthesizeLT(p.first, PrecedenceEnum::Add);
515  } else if (eq(*(p.second), *minus_one)) {
516  t = "-" + parenthesizeLT(p.first, PrecedenceEnum::Mul);
517  } else {
518  t = parenthesizeLT(p.second, PrecedenceEnum::Mul) + print_mul()
519  + parenthesizeLT(p.first, PrecedenceEnum::Mul);
520  }
521 
522  if (not first) {
523  if (t[0] == '-') {
524  o << " - " << t.substr(1);
525  } else {
526  o << " + " << t;
527  }
528  } else {
529  o << t;
530  first = false;
531  }
532  }
533  str_ = o.str();
534 }
535 
536 void StrPrinter::_print_pow(std::ostringstream &o, const RCP<const Basic> &a,
537  const RCP<const Basic> &b)
538 {
539  if (eq(*a, *E)) {
540  o << "exp(" << apply(b) << ")";
541  } else if (eq(*b, *rational(1, 2))) {
542  o << "sqrt(" << apply(a) << ")";
543  } else {
544  o << parenthesizeLE(a, PrecedenceEnum::Pow);
545  o << "**";
546  o << parenthesizeLE(b, PrecedenceEnum::Pow);
547  }
548 }
549 
550 void StrPrinter::bvisit(const Mul &x)
551 {
552  std::ostringstream o, o2;
553  bool num = false;
554  unsigned den = 0;
555 
556  if (eq(*(x.get_coef()), *minus_one)) {
557  o << "-";
558  } else if (neq(*(x.get_coef()), *one)) {
559  if (not split_mul_coef()) {
560  o << parenthesizeLT(x.get_coef(), PrecedenceEnum::Mul)
561  << print_mul();
562  num = true;
563  } else {
564  RCP<const Basic> numer, denom;
565  as_numer_denom(x.get_coef(), outArg(numer), outArg(denom));
566  if (neq(*numer, *one)) {
567  num = true;
568  o << parenthesizeLT(numer, PrecedenceEnum::Mul) << print_mul();
569  }
570  if (neq(*denom, *one)) {
571  den++;
572  o2 << parenthesizeLT(denom, PrecedenceEnum::Mul) << print_mul();
573  }
574  }
575  }
576 
577  for (const auto &p : x.get_dict()) {
578  if ((is_a<Integer>(*p.second) or is_a<Rational>(*p.second))
579  and down_cast<const Number &>(*p.second).is_negative()
580  and neq(*(p.first), *E)) {
581  if (eq(*(p.second), *minus_one)) {
582  o2 << parenthesizeLT(p.first, PrecedenceEnum::Mul);
583  } else {
584  _print_pow(o2, p.first, neg(p.second));
585  }
586  o2 << print_mul();
587  den++;
588  } else {
589  if (eq(*(p.second), *one)) {
590  o << parenthesizeLT(p.first, PrecedenceEnum::Mul);
591  } else {
592  _print_pow(o, p.first, p.second);
593  }
594  o << print_mul();
595  num = true;
596  }
597  }
598 
599  if (not num) {
600  o << "1" << print_mul();
601  }
602 
603  std::string s = o.str();
604  s = s.substr(0, s.size() - 1);
605 
606  if (den != 0) {
607  std::string s2 = o2.str();
608  s2 = s2.substr(0, s2.size() - 1);
609  if (den > 1) {
610  str_ = print_div(s, s2, true);
611  } else {
612  str_ = print_div(s, s2, false);
613  }
614  } else {
615  str_ = s;
616  }
617 }
618 
619 std::string StrPrinter::print_div(const std::string &num,
620  const std::string &den, bool paren)
621 {
622  if (paren) {
623  return num + "/" + parenthesize(den);
624  } else {
625  return num + "/" + den;
626  }
627 }
628 
629 bool StrPrinter::split_mul_coef()
630 {
631  return false;
632 }
633 
634 void StrPrinter::bvisit(const Pow &x)
635 {
637  _print_pow(o, x.get_base(), x.get_exp());
638  str_ = o.str();
639 }
640 
641 template <typename T>
642 char _print_sign(const T &i)
643 {
644  if (i < 0) {
645  return '-';
646  } else {
647  return '+';
648  }
649 }
650 
651 void StrPrinter::bvisit(const GaloisField &x)
652 {
654  // bool variable needed to take care of cases like -5, -x, -3*x etc.
655  bool first = true;
656  // we iterate over the map in reverse order so that highest degree gets
657  // printed first
658  auto dict = x.get_dict();
659  if (x.get_dict().size() == 0)
660  s << "0";
661  else {
662  for (auto it = dict.size(); it-- != 0;) {
663  if (dict[it] == 0)
664  continue;
665  // if exponent is 0, then print only coefficient
666  if (it == 0) {
667  if (first) {
668  s << dict[it];
669  } else {
670  s << " " << _print_sign(dict[it]) << " "
671  << mp_abs(dict[it]);
672  }
673  first = false;
674  break;
675  }
676  // if the coefficient of a term is +1 or -1
677  if (mp_abs(dict[it]) == 1) {
678  // in cases of -x, print -x
679  // in cases of x**2 - x, print - x
680  if (first) {
681  if (dict[it] == -1)
682  s << "-";
683  s << detail::poly_print(x.get_var());
684  } else {
685  s << " " << _print_sign(dict[it]) << " "
686  << detail::poly_print(x.get_var());
687  }
688  }
689  // same logic is followed as above
690  else {
691  // in cases of -2*x, print -2*x
692  // in cases of x**2 - 2*x, print - 2*x
693  if (first) {
694  s << dict[it] << "*" << detail::poly_print(x.get_var());
695  } else {
696  s << " " << _print_sign(dict[it]) << " " << mp_abs(dict[it])
697  << "*" << detail::poly_print(x.get_var());
698  }
699  }
700  // if exponent is not 1, print the exponent;
701  if (it != 1) {
702  s << "**" << it;
703  }
704  // corner cases of only first term handled successfully, switch the
705  // bool
706  first = false;
707  }
708  }
709  str_ = s.str();
710 }
711 
712 // Printing of Integer and Rational Polynomials, tests taken
713 // from SymPy and printing ensures that there is compatibility
714 template <typename P>
715 std::string upoly_print(const P &x)
716 {
718  // bool variable needed to take care of cases like -5, -x, -3*x etc.
719  bool first = true;
720  // we iterate over the map in reverse order so that highest degree gets
721  // printed first
722  for (auto it = x.obegin(); it != x.oend(); ++it) {
723  auto m = it->second;
724  // if exponent is 0, then print only coefficient
725  if (it->first == 0) {
726  if (first) {
727  s << m;
728  } else {
729  s << " " << _print_sign(m) << " " << mp_abs(m);
730  }
731  first = false;
732  continue;
733  }
734  // if the coefficient of a term is +1 or -1
735  if (mp_abs(m) == 1) {
736  // in cases of -x, print -x
737  // in cases of x**2 - x, print - x
738  if (first) {
739  if (m == -1)
740  s << "-";
741  s << detail::poly_print(x.get_var());
742  } else {
743  s << " " << _print_sign(m) << " "
744  << detail::poly_print(x.get_var());
745  }
746  }
747  // same logic is followed as above
748  else {
749  // in cases of -2*x, print -2*x
750  // in cases of x**2 - 2*x, print - 2*x
751  if (first) {
752  s << m << "*" << detail::poly_print(x.get_var());
753  } else {
754  s << " " << _print_sign(m) << " " << mp_abs(m) << "*"
755  << detail::poly_print(x.get_var());
756  }
757  }
758  // if exponent is not 1, print the exponent;
759  if (it->first != 1) {
760  s << "**" << it->first;
761  }
762  // corner cases of only first term handled successfully, switch the bool
763  first = false;
764  }
765  if (x.size() == 0)
766  s << "0";
767  return s.str();
768 }
769 
770 void StrPrinter::bvisit(const UIntPoly &x)
771 {
772  str_ = upoly_print<UIntPoly>(x);
773 }
774 
775 void StrPrinter::bvisit(const URatPoly &x)
776 {
777  str_ = upoly_print<URatPoly>(x);
778 }
779 
780 #ifdef HAVE_SYMENGINE_FLINT
781 void StrPrinter::bvisit(const UIntPolyFlint &x)
782 {
783  str_ = upoly_print<UIntPolyFlint>(x);
784 }
785 void StrPrinter::bvisit(const URatPolyFlint &x)
786 {
787  str_ = upoly_print<URatPolyFlint>(x);
788 }
789 #endif
790 
791 #ifdef HAVE_SYMENGINE_PIRANHA
792 void StrPrinter::bvisit(const UIntPolyPiranha &x)
793 {
794  str_ = upoly_print<UIntPolyPiranha>(x);
795 }
796 void StrPrinter::bvisit(const URatPolyPiranha &x)
797 {
798  str_ = upoly_print<URatPolyPiranha>(x);
799 }
800 #endif
801 
802 // UExprPoly printing, tests taken from SymPy and printing ensures
803 // that there is compatibility
804 void StrPrinter::bvisit(const UExprPoly &x)
805 {
807  if (x.get_dict().size() == 0)
808  s << "0";
809  else
810  s << x.get_poly().__str__(detail::poly_print(x.get_var()));
811  str_ = s.str();
812 }
813 
814 void StrPrinter::bvisit(const UnivariateSeries &x)
815 {
817  o << x.get_poly().__str__(x.get_var()) << " + O(" << x.get_var() << "**"
818  << x.get_degree() << ")";
819  str_ = o.str();
820 }
821 
822 #ifdef HAVE_SYMENGINE_PIRANHA
823 void StrPrinter::bvisit(const URatPSeriesPiranha &x)
824 {
826  o << x.get_poly() << " + O(" << x.get_var() << "**" << x.get_degree()
827  << ")";
828  str_ = o.str();
829 }
830 void StrPrinter::bvisit(const UPSeriesPiranha &x)
831 {
833  o << x.get_poly() << " + O(" << x.get_var() << "**" << x.get_degree()
834  << ")";
835  str_ = o.str();
836 }
837 #endif
838 
839 void StrPrinter::bvisit(const Constant &x)
840 {
841  str_ = x.get_name();
842 }
843 
844 std::string StrPrinter::apply(const vec_basic &d)
845 {
847  for (auto p = d.begin(); p != d.end(); p++) {
848  if (p != d.begin()) {
849  o << ", ";
850  }
851  o << this->apply(*p);
852  }
853  return o.str();
854 }
855 
856 void StrPrinter::bvisit(const Function &x)
857 {
859  o << names_[x.get_type_code()];
860  vec_basic vec = x.get_args();
861  o << parenthesize(apply(vec));
862  str_ = o.str();
863 }
864 
865 void StrPrinter::bvisit(const FunctionSymbol &x)
866 {
868  o << x.get_name();
869  vec_basic vec = x.get_args();
870  o << parenthesize(apply(vec));
871  str_ = o.str();
872 }
873 
874 void StrPrinter::bvisit(const Derivative &x)
875 {
877  o << "Derivative(" << this->apply(x.get_arg());
878  auto m1 = x.get_symbols();
879  for (const auto &elem : m1) {
880  o << ", " << this->apply(elem);
881  }
882  o << ")";
883  str_ = o.str();
884 }
885 
886 void StrPrinter::bvisit(const Subs &x)
887 {
888  std::ostringstream o, vars, point;
889  for (auto p = x.get_dict().begin(); p != x.get_dict().end(); p++) {
890  if (p != x.get_dict().begin()) {
891  vars << ", ";
892  point << ", ";
893  }
894  vars << apply(p->first);
895  point << apply(p->second);
896  }
897  o << "Subs(" << apply(x.get_arg()) << ", (" << vars.str() << "), ("
898  << point.str() << "))";
899  str_ = o.str();
900 }
901 
902 void StrPrinter::bvisit(const NumberWrapper &x)
903 {
904  str_ = x.__str__();
905 }
906 
907 void StrPrinter::bvisit(const MIntPoly &x)
908 {
910  bool first = true; // is this the first term being printed out?
911  // To change the ordering in which the terms will print out, change
912  // vec_uint_compare in dict.h
913  std::vector<vec_uint> v = sorted_keys(x.get_poly().dict_);
914 
915  for (vec_uint exps : v) {
916  integer_class c = x.get_poly().dict_.find(exps)->second;
917  if (!first) {
918  s << " " << _print_sign(c) << " ";
919  } else if (c < 0) {
920  s << "-";
921  }
922 
923  unsigned int i = 0;
924  std::ostringstream expr;
925  bool first_var = true;
926  for (auto it : x.get_vars()) {
927  if (exps[i] != 0) {
928  if (!first_var) {
929  expr << "*";
930  }
931  expr << it->__str__();
932  if (exps[i] > 1)
933  expr << "**" << exps[i];
934  first_var = false;
935  }
936  i++;
937  }
938  if (mp_abs(c) != 1) {
939  s << mp_abs(c);
940  if (!expr.str().empty()) {
941  s << "*";
942  }
943  } else if (expr.str().empty()) {
944  s << "1";
945  }
946  s << expr.str();
947  first = false;
948  }
949 
950  if (s.str().empty())
951  s << "0";
952  str_ = s.str();
953 }
954 
955 void StrPrinter::bvisit(const MExprPoly &x)
956 {
958  bool first = true; // is this the first term being printed out?
959  // To change the ordering in which the terms will print out, change
960  // vec_uint_compare in dict.h
961  std::vector<vec_int> v = sorted_keys(x.get_poly().dict_);
962 
963  for (vec_int exps : v) {
964  Expression c = x.get_poly().dict_.find(exps)->second;
965  std::string t = parenthesizeLT(c.get_basic(), PrecedenceEnum::Mul);
966  if ('-' == t[0] && !first) {
967  s << " - ";
968  t = t.substr(1);
969  } else if (!first) {
970  s << " + ";
971  }
972  unsigned int i = 0;
973  std::ostringstream expr;
974  bool first_var = true;
975  for (auto it : x.get_vars()) {
976  if (exps[i] != 0) {
977  if (!first_var) {
978  expr << "*";
979  }
980  expr << it->__str__();
981  if (exps[i] > 1 or exps[i] < 0)
982  expr << "**" << exps[i];
983  first_var = false;
984  }
985  i++;
986  }
987  if (c != 1 && c != -1) {
988  s << t;
989  if (!expr.str().empty()) {
990  s << "*";
991  }
992  } else if (expr.str().empty()) {
993  s << "1";
994  }
995  s << expr.str();
996  first = false;
997  }
998 
999  if (s.str().empty())
1000  s << "0";
1001  str_ = s.str();
1002 }
1003 
1004 std::string StrPrinter::parenthesizeLT(const RCP<const Basic> &x,
1005  PrecedenceEnum precedenceEnum)
1006 {
1007  Precedence prec;
1008  if (prec.getPrecedence(x) < precedenceEnum) {
1009  return parenthesize(apply(x));
1010  } else {
1011  return apply(x);
1012  }
1013 }
1014 
1015 std::string StrPrinter::parenthesizeLE(const RCP<const Basic> &x,
1016  PrecedenceEnum precedenceEnum)
1017 {
1018  Precedence prec;
1019  if (prec.getPrecedence(x) <= precedenceEnum) {
1020  return parenthesize(apply(x));
1021  } else {
1022  return apply(x);
1023  }
1024 }
1025 
1026 std::string StrPrinter::parenthesize(const std::string &x)
1027 {
1028  return "(" + x + ")";
1029 }
1030 
1031 std::string StrPrinter::apply(const RCP<const Basic> &b)
1032 {
1033  b->accept(*this);
1034  return str_;
1035 }
1036 
1037 std::string StrPrinter::apply(const Basic &b)
1038 {
1039  b.accept(*this);
1040  return str_;
1041 }
1042 
1043 std::vector<std::string> init_str_printer_names()
1044 {
1046  names.assign(TypeID_Count, "");
1047  names[SYMENGINE_SIN] = "sin";
1048  names[SYMENGINE_COS] = "cos";
1049  names[SYMENGINE_TAN] = "tan";
1050  names[SYMENGINE_COT] = "cot";
1051  names[SYMENGINE_CSC] = "csc";
1052  names[SYMENGINE_SEC] = "sec";
1053  names[SYMENGINE_ASIN] = "asin";
1054  names[SYMENGINE_ACOS] = "acos";
1055  names[SYMENGINE_ASEC] = "asec";
1056  names[SYMENGINE_ACSC] = "acsc";
1057  names[SYMENGINE_ATAN] = "atan";
1058  names[SYMENGINE_ACOT] = "acot";
1059  names[SYMENGINE_ATAN2] = "atan2";
1060  names[SYMENGINE_SINH] = "sinh";
1061  names[SYMENGINE_CSCH] = "csch";
1062  names[SYMENGINE_COSH] = "cosh";
1063  names[SYMENGINE_SECH] = "sech";
1064  names[SYMENGINE_TANH] = "tanh";
1065  names[SYMENGINE_COTH] = "coth";
1066  names[SYMENGINE_ASINH] = "asinh";
1067  names[SYMENGINE_ACSCH] = "acsch";
1068  names[SYMENGINE_ACOSH] = "acosh";
1069  names[SYMENGINE_ATANH] = "atanh";
1070  names[SYMENGINE_ACOTH] = "acoth";
1071  names[SYMENGINE_ASECH] = "asech";
1072  names[SYMENGINE_LOG] = "log";
1073  names[SYMENGINE_LAMBERTW] = "lambertw";
1074  names[SYMENGINE_ZETA] = "zeta";
1075  names[SYMENGINE_DIRICHLET_ETA] = "dirichlet_eta";
1076  names[SYMENGINE_KRONECKERDELTA] = "kroneckerdelta";
1077  names[SYMENGINE_LEVICIVITA] = "levicivita";
1078  names[SYMENGINE_FLOOR] = "floor";
1079  names[SYMENGINE_CEILING] = "ceiling";
1080  names[SYMENGINE_TRUNCATE] = "truncate";
1081  names[SYMENGINE_ERF] = "erf";
1082  names[SYMENGINE_ERFC] = "erfc";
1083  names[SYMENGINE_LOWERGAMMA] = "lowergamma";
1084  names[SYMENGINE_UPPERGAMMA] = "uppergamma";
1085  names[SYMENGINE_BETA] = "beta";
1086  names[SYMENGINE_LOGGAMMA] = "loggamma";
1087  names[SYMENGINE_LOG] = "log";
1088  names[SYMENGINE_POLYGAMMA] = "polygamma";
1089  names[SYMENGINE_GAMMA] = "gamma";
1090  names[SYMENGINE_ABS] = "abs";
1091  names[SYMENGINE_MAX] = "max";
1092  names[SYMENGINE_MIN] = "min";
1093  names[SYMENGINE_SIGN] = "sign";
1094  names[SYMENGINE_CONJUGATE] = "conjugate";
1095  names[SYMENGINE_PRIMEPI] = "primepi";
1096  names[SYMENGINE_PRIMORIAL] = "primorial";
1097  names[SYMENGINE_UNEVALUATED_EXPR] = "";
1098  return names;
1099 }
1100 
1101 const std::vector<std::string> StrPrinter::names_ = init_str_printer_names();
1102 
1103 std::string StrPrinter::print_mul()
1104 {
1105  return "*";
1106 }
1107 
1108 void JuliaStrPrinter::_print_pow(std::ostringstream &o,
1109  const RCP<const Basic> &a,
1110  const RCP<const Basic> &b)
1111 {
1112  if (eq(*a, *E)) {
1113  o << "exp(" << apply(b) << ")";
1114  } else if (eq(*b, *rational(1, 2))) {
1115  o << "sqrt(" << apply(a) << ")";
1116  } else {
1117  o << parenthesizeLE(a, PrecedenceEnum::Pow);
1118  o << "^";
1119  o << parenthesizeLE(b, PrecedenceEnum::Pow);
1120  }
1121 }
1122 
1123 void JuliaStrPrinter::bvisit(const Constant &x)
1124 {
1125  if (eq(x, *E)) {
1126  str_ = "exp(1)";
1127  } else {
1128  str_ = x.get_name();
1129  std::transform(str_.begin(), str_.end(), str_.begin(), ::tolower);
1130  }
1131 }
1132 
1133 void JuliaStrPrinter::bvisit(const NaN &x)
1134 {
1136  s << "NaN";
1137  str_ = s.str();
1138 }
1139 
1140 void JuliaStrPrinter::bvisit(const Infty &x)
1141 {
1143  if (x.is_negative_infinity())
1144  s << "-Inf";
1145  else if (x.is_positive_infinity())
1146  s << "Inf";
1147  else
1148  s << "zoo";
1149  str_ = s.str();
1150 }
1151 
1152 std::string JuliaStrPrinter::get_imag_symbol()
1153 {
1154  return "im";
1155 }
1156 
1157 std::string StrPrinter::get_imag_symbol()
1158 {
1159  return "I";
1160 }
1161 
1162 std::string str(const Basic &x)
1163 {
1164  StrPrinter strPrinter;
1165  return strPrinter.apply(x);
1166 }
1167 
1168 std::string julia_str(const Basic &x)
1169 {
1170  JuliaStrPrinter strPrinter;
1171  return strPrinter.apply(x);
1172 }
1173 } // namespace SymEngine
T assign(T... args)
T max(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
bool eq(const Basic &a, const Basic &b)
Checks equality for a and b
Definition: basic-inl.h:21
@ TypeID_Count
Definition: basic.h:52
bool neq(const Basic &a, const Basic &b)
Checks inequality for a and b
Definition: basic-inl.h:29
RCP< const Number > rational(long n, long d)
convenience creator from two longs
Definition: rational.h:328
RCP< const Basic > neg(const RCP< const Basic > &a)
Negation.
Definition: mul.cpp:449
T precision(T... args)
T lround(T... args)
T size(T... args)
T str(T... args)
Less operator (<) using cmp:
Definition: strprinter.cpp:8
bool operator()(const RCP< const Basic > &x, const RCP< const Basic > &y) const
true if x < y, false otherwise
Definition: strprinter.cpp:10
T substr(T... args)
T transform(T... args)