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