1use num_bigint::BigInt;
32use num_rational::Ratio;
33use serde::{Deserialize, Serialize};
34
35use crate::base::arena::Arena;
36use crate::base::node::{ExprId, ExprNode};
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
45#[serde(tag = "type")]
46pub enum ExprTree {
47 Num {
49 numer: String,
51 denom: String,
53 },
54 Symbol {
56 name: String,
58 },
59 Pi,
61 E,
63 ImaginaryUnit,
65 EulerGamma,
67 Catalan,
69 GoldenRatio,
71 PhysicalConstant {
73 name: String,
75 value: Box<ExprTree>,
77 },
78 Infinity,
80 NegInfinity,
82 ComplexInfinity,
84 NaN,
86 Add {
88 terms: Vec<ExprTree>,
90 },
91 Mul {
93 factors: Vec<ExprTree>,
95 },
96 Pow {
98 base: Box<ExprTree>,
100 exp: Box<ExprTree>,
102 },
103 Neg {
105 inner: Box<ExprTree>,
107 },
108 Sin {
110 arg: Box<ExprTree>,
112 },
113 Cos {
115 arg: Box<ExprTree>,
117 },
118 Tan {
120 arg: Box<ExprTree>,
122 },
123 Exp {
125 arg: Box<ExprTree>,
127 },
128 Ln {
130 arg: Box<ExprTree>,
132 },
133 Sqrt {
135 arg: Box<ExprTree>,
137 },
138 Abs {
140 arg: Box<ExprTree>,
142 },
143 Asin {
145 arg: Box<ExprTree>,
147 },
148 Acos {
150 arg: Box<ExprTree>,
152 },
153 Atan {
155 arg: Box<ExprTree>,
157 },
158 Atan2 {
160 y: Box<ExprTree>,
162 x: Box<ExprTree>,
164 },
165 Sinh {
167 arg: Box<ExprTree>,
169 },
170 Cosh {
172 arg: Box<ExprTree>,
174 },
175 Tanh {
177 arg: Box<ExprTree>,
179 },
180 Asinh {
182 arg: Box<ExprTree>,
184 },
185 Acosh {
187 arg: Box<ExprTree>,
189 },
190 Atanh {
192 arg: Box<ExprTree>,
194 },
195 Sign {
197 arg: Box<ExprTree>,
199 },
200 Heaviside {
202 arg: Box<ExprTree>,
204 },
205 DiracDelta {
207 arg: Box<ExprTree>,
209 },
210 Gamma {
212 arg: Box<ExprTree>,
214 },
215 LogGamma {
217 arg: Box<ExprTree>,
219 },
220 Digamma {
222 arg: Box<ExprTree>,
224 },
225 Erf {
227 arg: Box<ExprTree>,
229 },
230 Erfc {
232 arg: Box<ExprTree>,
234 },
235 LambertW {
237 arg: Box<ExprTree>,
239 },
240 Beta {
242 a: Box<ExprTree>,
244 b: Box<ExprTree>,
246 },
247 Re {
249 arg: Box<ExprTree>,
251 },
252 Im {
254 arg: Box<ExprTree>,
256 },
257 Conjugate {
259 arg: Box<ExprTree>,
261 },
262 Arg {
264 arg: Box<ExprTree>,
266 },
267 Si {
269 arg: Box<ExprTree>,
271 },
272 Ci {
274 arg: Box<ExprTree>,
276 },
277 Ei {
279 arg: Box<ExprTree>,
281 },
282 Li {
284 arg: Box<ExprTree>,
286 },
287 Zeta {
289 arg: Box<ExprTree>,
291 },
292 Polygamma {
294 n: Box<ExprTree>,
296 arg: Box<ExprTree>,
298 },
299 KroneckerDelta {
301 i: Box<ExprTree>,
303 j: Box<ExprTree>,
305 },
306 Floor {
308 arg: Box<ExprTree>,
310 },
311 Ceiling {
313 arg: Box<ExprTree>,
315 },
316 Min {
318 args: Vec<ExprTree>,
320 },
321 Max {
323 args: Vec<ExprTree>,
325 },
326 BoolTrue,
328 BoolFalse,
330 Gt {
332 lhs: Box<ExprTree>,
334 rhs: Box<ExprTree>,
336 },
337 Ge {
339 lhs: Box<ExprTree>,
341 rhs: Box<ExprTree>,
343 },
344 Eq_ {
346 lhs: Box<ExprTree>,
348 rhs: Box<ExprTree>,
350 },
351 Ne {
353 lhs: Box<ExprTree>,
355 rhs: Box<ExprTree>,
357 },
358 And {
360 args: Vec<ExprTree>,
362 },
363 Or {
365 args: Vec<ExprTree>,
367 },
368 Not {
370 arg: Box<ExprTree>,
372 },
373 Piecewise {
375 pieces: Vec<(ExprTree, ExprTree)>,
377 },
378 Apply {
380 name: String,
382 args: Vec<ExprTree>,
384 },
385 Derivative {
387 body: Box<ExprTree>,
389 var: Box<ExprTree>,
391 },
392 Integral {
394 body: Box<ExprTree>,
396 var: Box<ExprTree>,
398 },
399 DefiniteIntegral {
401 body: Box<ExprTree>,
403 var: Box<ExprTree>,
405 lower: Box<ExprTree>,
407 upper: Box<ExprTree>,
409 },
410 Sum {
412 body: Box<ExprTree>,
414 var: Box<ExprTree>,
416 lower: Box<ExprTree>,
418 upper: Box<ExprTree>,
420 },
421 Product_ {
423 body: Box<ExprTree>,
425 var: Box<ExprTree>,
427 lower: Box<ExprTree>,
429 upper: Box<ExprTree>,
431 },
432 EmptySet,
434 UniversalSet,
436 Interval {
439 start: Box<ExprTree>,
441 end: Box<ExprTree>,
443 flags: u8,
445 },
446 FiniteSet {
448 elements: Vec<ExprTree>,
450 },
451 SetUnion {
453 sets: Vec<ExprTree>,
455 },
456 SetIntersection {
458 sets: Vec<ExprTree>,
460 },
461 SetComplement {
463 set: Box<ExprTree>,
465 universe: Box<ExprTree>,
467 },
468 Limit {
470 body: Box<ExprTree>,
472 var: Box<ExprTree>,
474 point: Box<ExprTree>,
476 },
477 Series {
479 body: Box<ExprTree>,
481 var: Box<ExprTree>,
483 point: Box<ExprTree>,
485 order: Box<ExprTree>,
487 },
488 LaplaceTransform {
490 body: Box<ExprTree>,
492 t: Box<ExprTree>,
494 s: Box<ExprTree>,
496 },
497 InverseLaplaceTransform {
499 body: Box<ExprTree>,
501 s: Box<ExprTree>,
503 t: Box<ExprTree>,
505 },
506 Residue {
508 body: Box<ExprTree>,
510 var: Box<ExprTree>,
512 point: Box<ExprTree>,
514 },
515 RootOf {
517 poly: Box<ExprTree>,
519 index: Box<ExprTree>,
521 },
522 DSolve {
524 expr: Box<ExprTree>,
526 func: Box<ExprTree>,
528 var: Box<ExprTree>,
530 },
531 RootSum {
533 poly: Box<ExprTree>,
535 body: Box<ExprTree>,
537 sumvar: Box<ExprTree>,
539 },
540 ConditionSet {
542 var: Box<ExprTree>,
544 condition: Box<ExprTree>,
546 },
547}
548
549pub(crate) fn expr_to_tree(arena: &Arena, id: ExprId) -> ExprTree {
558 match arena.node(id).clone() {
559 ExprNode::Num(nid) => {
560 let r = arena.num(nid);
561 ExprTree::Num {
562 numer: r.numer().to_string(),
563 denom: r.denom().to_string(),
564 }
565 }
566 ExprNode::Symbol(sid) => ExprTree::Symbol {
567 name: arena.symbol_name(sid).to_owned(),
568 },
569 ExprNode::Pi => ExprTree::Pi,
570 ExprNode::E => ExprTree::E,
571 ExprNode::ImaginaryUnit => ExprTree::ImaginaryUnit,
572 ExprNode::EulerGamma => ExprTree::EulerGamma,
573 ExprNode::Catalan => ExprTree::Catalan,
574 ExprNode::GoldenRatio => ExprTree::GoldenRatio,
575 ExprNode::PhysicalConstant(name_id, value_id) => ExprTree::PhysicalConstant {
576 name: arena.symbol_name(name_id).to_owned(),
577 value: Box::new(expr_to_tree(arena, value_id)),
578 },
579 ExprNode::Infinity => ExprTree::Infinity,
580 ExprNode::NegInfinity => ExprTree::NegInfinity,
581 ExprNode::ComplexInfinity => ExprTree::ComplexInfinity,
582 ExprNode::NaN => ExprTree::NaN,
583 ExprNode::Add(children) => ExprTree::Add {
584 terms: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
585 },
586 ExprNode::Mul(children) => ExprTree::Mul {
587 factors: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
588 },
589 ExprNode::Pow(base, exp) => ExprTree::Pow {
590 base: Box::new(expr_to_tree(arena, base)),
591 exp: Box::new(expr_to_tree(arena, exp)),
592 },
593 ExprNode::Neg(inner) => ExprTree::Neg {
594 inner: Box::new(expr_to_tree(arena, inner)),
595 },
596 ExprNode::Sin(x) => ExprTree::Sin {
597 arg: Box::new(expr_to_tree(arena, x)),
598 },
599 ExprNode::Cos(x) => ExprTree::Cos {
600 arg: Box::new(expr_to_tree(arena, x)),
601 },
602 ExprNode::Tan(x) => ExprTree::Tan {
603 arg: Box::new(expr_to_tree(arena, x)),
604 },
605 ExprNode::Exp(x) => ExprTree::Exp {
606 arg: Box::new(expr_to_tree(arena, x)),
607 },
608 ExprNode::Ln(x) => ExprTree::Ln {
609 arg: Box::new(expr_to_tree(arena, x)),
610 },
611 ExprNode::Abs(x) => ExprTree::Abs {
612 arg: Box::new(expr_to_tree(arena, x)),
613 },
614 ExprNode::Asin(x) => ExprTree::Asin {
615 arg: Box::new(expr_to_tree(arena, x)),
616 },
617 ExprNode::Acos(x) => ExprTree::Acos {
618 arg: Box::new(expr_to_tree(arena, x)),
619 },
620 ExprNode::Atan(x) => ExprTree::Atan {
621 arg: Box::new(expr_to_tree(arena, x)),
622 },
623 ExprNode::Atan2(y, x) => ExprTree::Atan2 {
624 y: Box::new(expr_to_tree(arena, y)),
625 x: Box::new(expr_to_tree(arena, x)),
626 },
627 ExprNode::Sinh(x) => ExprTree::Sinh {
628 arg: Box::new(expr_to_tree(arena, x)),
629 },
630 ExprNode::Cosh(x) => ExprTree::Cosh {
631 arg: Box::new(expr_to_tree(arena, x)),
632 },
633 ExprNode::Tanh(x) => ExprTree::Tanh {
634 arg: Box::new(expr_to_tree(arena, x)),
635 },
636 ExprNode::Asinh(x) => ExprTree::Asinh {
637 arg: Box::new(expr_to_tree(arena, x)),
638 },
639 ExprNode::Acosh(x) => ExprTree::Acosh {
640 arg: Box::new(expr_to_tree(arena, x)),
641 },
642 ExprNode::Atanh(x) => ExprTree::Atanh {
643 arg: Box::new(expr_to_tree(arena, x)),
644 },
645 ExprNode::Sign(x) => ExprTree::Sign {
646 arg: Box::new(expr_to_tree(arena, x)),
647 },
648 ExprNode::Heaviside(x) => ExprTree::Heaviside {
649 arg: Box::new(expr_to_tree(arena, x)),
650 },
651 ExprNode::DiracDelta(x) => ExprTree::DiracDelta {
652 arg: Box::new(expr_to_tree(arena, x)),
653 },
654 ExprNode::Gamma(x) => ExprTree::Gamma {
655 arg: Box::new(expr_to_tree(arena, x)),
656 },
657 ExprNode::LogGamma(x) => ExprTree::LogGamma {
658 arg: Box::new(expr_to_tree(arena, x)),
659 },
660 ExprNode::Digamma(x) => ExprTree::Digamma {
661 arg: Box::new(expr_to_tree(arena, x)),
662 },
663 ExprNode::Erf(x) => ExprTree::Erf {
664 arg: Box::new(expr_to_tree(arena, x)),
665 },
666 ExprNode::Erfc(x) => ExprTree::Erfc {
667 arg: Box::new(expr_to_tree(arena, x)),
668 },
669 ExprNode::LambertW(x) => ExprTree::LambertW {
670 arg: Box::new(expr_to_tree(arena, x)),
671 },
672 ExprNode::Beta(a, b) => ExprTree::Beta {
673 a: Box::new(expr_to_tree(arena, a)),
674 b: Box::new(expr_to_tree(arena, b)),
675 },
676 ExprNode::Re(x) => ExprTree::Re {
677 arg: Box::new(expr_to_tree(arena, x)),
678 },
679 ExprNode::Im(x) => ExprTree::Im {
680 arg: Box::new(expr_to_tree(arena, x)),
681 },
682 ExprNode::Conjugate(x) => ExprTree::Conjugate {
683 arg: Box::new(expr_to_tree(arena, x)),
684 },
685 ExprNode::Arg(x) => ExprTree::Arg {
686 arg: Box::new(expr_to_tree(arena, x)),
687 },
688 ExprNode::Si(x) => ExprTree::Si {
689 arg: Box::new(expr_to_tree(arena, x)),
690 },
691 ExprNode::Ci(x) => ExprTree::Ci {
692 arg: Box::new(expr_to_tree(arena, x)),
693 },
694 ExprNode::Ei(x) => ExprTree::Ei {
695 arg: Box::new(expr_to_tree(arena, x)),
696 },
697 ExprNode::Li(x) => ExprTree::Li {
698 arg: Box::new(expr_to_tree(arena, x)),
699 },
700 ExprNode::Zeta(x) => ExprTree::Zeta {
701 arg: Box::new(expr_to_tree(arena, x)),
702 },
703 ExprNode::Polygamma(n, x) => ExprTree::Polygamma {
704 n: Box::new(expr_to_tree(arena, n)),
705 arg: Box::new(expr_to_tree(arena, x)),
706 },
707 ExprNode::KroneckerDelta(i, j) => ExprTree::KroneckerDelta {
708 i: Box::new(expr_to_tree(arena, i)),
709 j: Box::new(expr_to_tree(arena, j)),
710 },
711 ExprNode::Floor(x) => ExprTree::Floor {
712 arg: Box::new(expr_to_tree(arena, x)),
713 },
714 ExprNode::Ceiling(x) => ExprTree::Ceiling {
715 arg: Box::new(expr_to_tree(arena, x)),
716 },
717 ExprNode::Min(children) => ExprTree::Min {
718 args: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
719 },
720 ExprNode::Max(children) => ExprTree::Max {
721 args: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
722 },
723 ExprNode::Apply(sid, args) => ExprTree::Apply {
724 name: arena.symbol_name(sid).to_owned(),
725 args: args.iter().map(|&a| expr_to_tree(arena, a)).collect(),
726 },
727 ExprNode::Derivative(body, var) => ExprTree::Derivative {
728 body: Box::new(expr_to_tree(arena, body)),
729 var: Box::new(expr_to_tree(arena, var)),
730 },
731 ExprNode::Integral(body, var) => ExprTree::Integral {
732 body: Box::new(expr_to_tree(arena, body)),
733 var: Box::new(expr_to_tree(arena, var)),
734 },
735 ExprNode::DefiniteIntegral(body, var, lo, hi) => ExprTree::DefiniteIntegral {
736 body: Box::new(expr_to_tree(arena, body)),
737 var: Box::new(expr_to_tree(arena, var)),
738 lower: Box::new(expr_to_tree(arena, lo)),
739 upper: Box::new(expr_to_tree(arena, hi)),
740 },
741 ExprNode::Sum(body, var, lo, hi) => ExprTree::Sum {
742 body: Box::new(expr_to_tree(arena, body)),
743 var: Box::new(expr_to_tree(arena, var)),
744 lower: Box::new(expr_to_tree(arena, lo)),
745 upper: Box::new(expr_to_tree(arena, hi)),
746 },
747 ExprNode::Product_(body, var, lo, hi) => ExprTree::Product_ {
748 body: Box::new(expr_to_tree(arena, body)),
749 var: Box::new(expr_to_tree(arena, var)),
750 lower: Box::new(expr_to_tree(arena, lo)),
751 upper: Box::new(expr_to_tree(arena, hi)),
752 },
753 ExprNode::Factorial(x) => ExprTree::Apply {
754 name: "factorial".to_owned(),
755 args: vec![expr_to_tree(arena, x)],
756 },
757 ExprNode::Binomial(n, k) => ExprTree::Apply {
758 name: "binomial".to_owned(),
759 args: vec![expr_to_tree(arena, n), expr_to_tree(arena, k)],
760 },
761 ExprNode::BoolTrue => ExprTree::BoolTrue,
762 ExprNode::BoolFalse => ExprTree::BoolFalse,
763 ExprNode::Gt(a, b) => ExprTree::Gt {
764 lhs: Box::new(expr_to_tree(arena, a)),
765 rhs: Box::new(expr_to_tree(arena, b)),
766 },
767 ExprNode::Ge(a, b) => ExprTree::Ge {
768 lhs: Box::new(expr_to_tree(arena, a)),
769 rhs: Box::new(expr_to_tree(arena, b)),
770 },
771 ExprNode::Eq_(a, b) => ExprTree::Eq_ {
772 lhs: Box::new(expr_to_tree(arena, a)),
773 rhs: Box::new(expr_to_tree(arena, b)),
774 },
775 ExprNode::Ne(a, b) => ExprTree::Ne {
776 lhs: Box::new(expr_to_tree(arena, a)),
777 rhs: Box::new(expr_to_tree(arena, b)),
778 },
779 ExprNode::And(children) => ExprTree::And {
780 args: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
781 },
782 ExprNode::Or(children) => ExprTree::Or {
783 args: children.iter().map(|&c| expr_to_tree(arena, c)).collect(),
784 },
785 ExprNode::Not(x) => ExprTree::Not {
786 arg: Box::new(expr_to_tree(arena, x)),
787 },
788 ExprNode::Piecewise(children) => ExprTree::Piecewise {
789 pieces: children
790 .iter()
791 .map(|&(val, cond)| (expr_to_tree(arena, val), expr_to_tree(arena, cond)))
792 .collect(),
793 },
794 ExprNode::EmptySet => ExprTree::EmptySet,
795 ExprNode::UniversalSet => ExprTree::UniversalSet,
796 ExprNode::Interval(start, end, flags) => ExprTree::Interval {
797 start: Box::new(expr_to_tree(arena, start)),
798 end: Box::new(expr_to_tree(arena, end)),
799 flags,
800 },
801 ExprNode::FiniteSet(elems) => ExprTree::FiniteSet {
802 elements: elems.iter().map(|&e| expr_to_tree(arena, e)).collect(),
803 },
804 ExprNode::SetUnion(sets) => ExprTree::SetUnion {
805 sets: sets.iter().map(|&s| expr_to_tree(arena, s)).collect(),
806 },
807 ExprNode::SetIntersection(sets) => ExprTree::SetIntersection {
808 sets: sets.iter().map(|&s| expr_to_tree(arena, s)).collect(),
809 },
810 ExprNode::SetComplement(a, b) => ExprTree::SetComplement {
811 set: Box::new(expr_to_tree(arena, a)),
812 universe: Box::new(expr_to_tree(arena, b)),
813 },
814 ExprNode::Limit(body, var, point) => ExprTree::Limit {
815 body: Box::new(expr_to_tree(arena, body)),
816 var: Box::new(expr_to_tree(arena, var)),
817 point: Box::new(expr_to_tree(arena, point)),
818 },
819 ExprNode::Series(body, var, point, order) => ExprTree::Series {
820 body: Box::new(expr_to_tree(arena, body)),
821 var: Box::new(expr_to_tree(arena, var)),
822 point: Box::new(expr_to_tree(arena, point)),
823 order: Box::new(expr_to_tree(arena, order)),
824 },
825 ExprNode::LaplaceTransform(body, t, s) => ExprTree::LaplaceTransform {
826 body: Box::new(expr_to_tree(arena, body)),
827 t: Box::new(expr_to_tree(arena, t)),
828 s: Box::new(expr_to_tree(arena, s)),
829 },
830 ExprNode::InverseLaplaceTransform(body, s, t) => ExprTree::InverseLaplaceTransform {
831 body: Box::new(expr_to_tree(arena, body)),
832 s: Box::new(expr_to_tree(arena, s)),
833 t: Box::new(expr_to_tree(arena, t)),
834 },
835 ExprNode::Residue(body, var, point) => ExprTree::Residue {
836 body: Box::new(expr_to_tree(arena, body)),
837 var: Box::new(expr_to_tree(arena, var)),
838 point: Box::new(expr_to_tree(arena, point)),
839 },
840 ExprNode::RootOf(poly, index) => ExprTree::RootOf {
841 poly: Box::new(expr_to_tree(arena, poly)),
842 index: Box::new(expr_to_tree(arena, index)),
843 },
844 ExprNode::DSolve(expr, func, var) => ExprTree::DSolve {
845 expr: Box::new(expr_to_tree(arena, expr)),
846 func: Box::new(expr_to_tree(arena, func)),
847 var: Box::new(expr_to_tree(arena, var)),
848 },
849 ExprNode::RootSum(poly, body, sumvar) => ExprTree::RootSum {
850 poly: Box::new(expr_to_tree(arena, poly)),
851 body: Box::new(expr_to_tree(arena, body)),
852 sumvar: Box::new(expr_to_tree(arena, sumvar)),
853 },
854 ExprNode::ConditionSet(var, condition) => ExprTree::ConditionSet {
855 var: Box::new(expr_to_tree(arena, var)),
856 condition: Box::new(expr_to_tree(arena, condition)),
857 },
858 }
859}
860
861pub(crate) fn tree_to_expr(arena: &mut Arena, tree: &ExprTree) -> ExprId {
870 match tree {
871 ExprTree::Num { numer, denom } => {
872 let n: BigInt = numer.parse().unwrap_or_default();
873 let d: BigInt = denom.parse().unwrap_or_else(|_| BigInt::from(1));
874 let r = Ratio::new(n, d);
875 let nid = arena.intern_num(r);
876 arena.intern(ExprNode::Num(nid))
877 }
878 ExprTree::Symbol { name } => arena.symbol(name),
879 ExprTree::Pi => arena.pi,
880 ExprTree::E => arena.e_const,
881 ExprTree::ImaginaryUnit => arena.i_unit,
882 ExprTree::EulerGamma => arena.euler_gamma,
883 ExprTree::Catalan => arena.catalan,
884 ExprTree::GoldenRatio => arena.golden_ratio,
885 ExprTree::PhysicalConstant { name, value } => {
886 let val_id = tree_to_expr(arena, value);
887 arena.physical_constant(name, val_id)
888 }
889 ExprTree::Infinity => arena.infinity,
890 ExprTree::NegInfinity => arena.neg_infinity,
891 ExprTree::ComplexInfinity => arena.complex_infinity,
892 ExprTree::NaN => arena.nan,
893 ExprTree::Add { terms } => {
894 let ids: Vec<ExprId> = terms.iter().map(|t| tree_to_expr(arena, t)).collect();
895 arena.add(&ids)
896 }
897 ExprTree::Mul { factors } => {
898 let ids: Vec<ExprId> = factors.iter().map(|f| tree_to_expr(arena, f)).collect();
899 arena.mul(&ids)
900 }
901 ExprTree::Pow { base, exp } => {
902 let b = tree_to_expr(arena, base);
903 let e = tree_to_expr(arena, exp);
904 arena.pow(b, e)
905 }
906 ExprTree::Neg { inner } => {
907 let x = tree_to_expr(arena, inner);
908 arena.neg(x)
909 }
910 ExprTree::Sin { arg } => {
911 let x = tree_to_expr(arena, arg);
912 arena.sin(x)
913 }
914 ExprTree::Cos { arg } => {
915 let x = tree_to_expr(arena, arg);
916 arena.cos(x)
917 }
918 ExprTree::Tan { arg } => {
919 let x = tree_to_expr(arena, arg);
920 arena.tan(x)
921 }
922 ExprTree::Exp { arg } => {
923 let x = tree_to_expr(arena, arg);
924 arena.exp(x)
925 }
926 ExprTree::Ln { arg } => {
927 let x = tree_to_expr(arena, arg);
928 arena.ln(x)
929 }
930 ExprTree::Sqrt { arg } => {
931 let x = tree_to_expr(arena, arg);
933 arena.sqrt(x) }
935 ExprTree::Abs { arg } => {
936 let x = tree_to_expr(arena, arg);
937 arena.abs(x)
938 }
939 ExprTree::Asin { arg } => {
940 let x = tree_to_expr(arena, arg);
941 arena.asin(x)
942 }
943 ExprTree::Acos { arg } => {
944 let x = tree_to_expr(arena, arg);
945 arena.acos(x)
946 }
947 ExprTree::Atan { arg } => {
948 let x = tree_to_expr(arena, arg);
949 arena.atan(x)
950 }
951 ExprTree::Atan2 { y, x } => {
952 let yid = tree_to_expr(arena, y);
953 let xid = tree_to_expr(arena, x);
954 arena.atan2(yid, xid)
955 }
956 ExprTree::Sinh { arg } => {
957 let x = tree_to_expr(arena, arg);
958 arena.sinh(x)
959 }
960 ExprTree::Cosh { arg } => {
961 let x = tree_to_expr(arena, arg);
962 arena.cosh(x)
963 }
964 ExprTree::Tanh { arg } => {
965 let x = tree_to_expr(arena, arg);
966 arena.tanh(x)
967 }
968 ExprTree::Asinh { arg } => {
969 let x = tree_to_expr(arena, arg);
970 arena.asinh(x)
971 }
972 ExprTree::Acosh { arg } => {
973 let x = tree_to_expr(arena, arg);
974 arena.acosh(x)
975 }
976 ExprTree::Atanh { arg } => {
977 let x = tree_to_expr(arena, arg);
978 arena.atanh(x)
979 }
980 ExprTree::Sign { arg } => {
981 let x = tree_to_expr(arena, arg);
982 arena.sign(x)
983 }
984 ExprTree::Heaviside { arg } => {
985 let x = tree_to_expr(arena, arg);
986 arena.heaviside(x)
987 }
988 ExprTree::DiracDelta { arg } => {
989 let x = tree_to_expr(arena, arg);
990 arena.dirac_delta(x)
991 }
992 ExprTree::Gamma { arg } => {
993 let x = tree_to_expr(arena, arg);
994 arena.gamma(x)
995 }
996 ExprTree::LogGamma { arg } => {
997 let x = tree_to_expr(arena, arg);
998 arena.log_gamma(x)
999 }
1000 ExprTree::Digamma { arg } => {
1001 let x = tree_to_expr(arena, arg);
1002 arena.digamma(x)
1003 }
1004 ExprTree::Erf { arg } => {
1005 let x = tree_to_expr(arena, arg);
1006 arena.erf(x)
1007 }
1008 ExprTree::Erfc { arg } => {
1009 let x = tree_to_expr(arena, arg);
1010 arena.erfc(x)
1011 }
1012 ExprTree::LambertW { arg } => {
1013 let x = tree_to_expr(arena, arg);
1014 arena.lambertw(x)
1015 }
1016 ExprTree::Beta { a, b } => {
1017 let aid = tree_to_expr(arena, a);
1018 let bid = tree_to_expr(arena, b);
1019 arena.beta(aid, bid)
1020 }
1021 ExprTree::Re { arg } => {
1022 let x = tree_to_expr(arena, arg);
1023 arena.re(x)
1024 }
1025 ExprTree::Im { arg } => {
1026 let x = tree_to_expr(arena, arg);
1027 arena.im(x)
1028 }
1029 ExprTree::Conjugate { arg } => {
1030 let x = tree_to_expr(arena, arg);
1031 arena.conjugate(x)
1032 }
1033 ExprTree::Arg { arg } => {
1034 let x = tree_to_expr(arena, arg);
1035 arena.arg(x)
1036 }
1037 ExprTree::Si { arg } => {
1038 let x = tree_to_expr(arena, arg);
1039 arena.si(x)
1040 }
1041 ExprTree::Ci { arg } => {
1042 let x = tree_to_expr(arena, arg);
1043 arena.ci(x)
1044 }
1045 ExprTree::Ei { arg } => {
1046 let x = tree_to_expr(arena, arg);
1047 arena.ei(x)
1048 }
1049 ExprTree::Li { arg } => {
1050 let x = tree_to_expr(arena, arg);
1051 arena.li(x)
1052 }
1053 ExprTree::Zeta { arg } => {
1054 let x = tree_to_expr(arena, arg);
1055 arena.zeta(x)
1056 }
1057 ExprTree::Polygamma { n, arg } => {
1058 let nid = tree_to_expr(arena, n);
1059 let x = tree_to_expr(arena, arg);
1060 arena.polygamma(nid, x)
1061 }
1062 ExprTree::KroneckerDelta { i, j } => {
1063 let iid = tree_to_expr(arena, i);
1064 let jid = tree_to_expr(arena, j);
1065 arena.kronecker_delta(iid, jid)
1066 }
1067 ExprTree::Floor { arg } => {
1068 let x = tree_to_expr(arena, arg);
1069 arena.floor(x)
1070 }
1071 ExprTree::Ceiling { arg } => {
1072 let x = tree_to_expr(arena, arg);
1073 arena.ceiling(x)
1074 }
1075 ExprTree::Min { args } => {
1076 let ids: smallvec::SmallVec<[ExprId; 4]> =
1077 args.iter().map(|a| tree_to_expr(arena, a)).collect();
1078 arena.intern(ExprNode::Min(ids))
1079 }
1080 ExprTree::Max { args } => {
1081 let ids: smallvec::SmallVec<[ExprId; 4]> =
1082 args.iter().map(|a| tree_to_expr(arena, a)).collect();
1083 arena.intern(ExprNode::Max(ids))
1084 }
1085 ExprTree::Apply { name, args } => {
1086 let sym_id = arena.symbols.intern(name);
1087 let arg_ids: Vec<ExprId> = args.iter().map(|a| tree_to_expr(arena, a)).collect();
1088 let sv: smallvec::SmallVec<[ExprId; 2]> = arg_ids.into_iter().collect();
1089 arena.intern(ExprNode::Apply(sym_id, sv))
1090 }
1091 ExprTree::Derivative { body, var } => {
1092 let b = tree_to_expr(arena, body);
1093 let v = tree_to_expr(arena, var);
1094 arena.intern(ExprNode::Derivative(b, v))
1095 }
1096 ExprTree::Integral { body, var } => {
1097 let b = tree_to_expr(arena, body);
1098 let v = tree_to_expr(arena, var);
1099 arena.intern(ExprNode::Integral(b, v))
1100 }
1101 ExprTree::DefiniteIntegral {
1102 body,
1103 var,
1104 lower,
1105 upper,
1106 } => {
1107 let b = tree_to_expr(arena, body);
1108 let v = tree_to_expr(arena, var);
1109 let lo = tree_to_expr(arena, lower);
1110 let hi = tree_to_expr(arena, upper);
1111 arena.definite_integral(b, v, lo, hi)
1112 }
1113 ExprTree::Sum {
1114 body,
1115 var,
1116 lower,
1117 upper,
1118 } => {
1119 let b = tree_to_expr(arena, body);
1120 let v = tree_to_expr(arena, var);
1121 let lo = tree_to_expr(arena, lower);
1122 let hi = tree_to_expr(arena, upper);
1123 arena.intern(ExprNode::Sum(b, v, lo, hi))
1124 }
1125 ExprTree::Product_ {
1126 body,
1127 var,
1128 lower,
1129 upper,
1130 } => {
1131 let b = tree_to_expr(arena, body);
1132 let v = tree_to_expr(arena, var);
1133 let lo = tree_to_expr(arena, lower);
1134 let hi = tree_to_expr(arena, upper);
1135 arena.intern(ExprNode::Product_(b, v, lo, hi))
1136 }
1137 ExprTree::BoolTrue => arena.bool_true,
1138 ExprTree::BoolFalse => arena.bool_false,
1139 ExprTree::Gt { lhs, rhs } => {
1140 let l = tree_to_expr(arena, lhs);
1141 let r = tree_to_expr(arena, rhs);
1142 arena.gt(l, r)
1143 }
1144 ExprTree::Ge { lhs, rhs } => {
1145 let l = tree_to_expr(arena, lhs);
1146 let r = tree_to_expr(arena, rhs);
1147 arena.ge(l, r)
1148 }
1149 ExprTree::Eq_ { lhs, rhs } => {
1150 let l = tree_to_expr(arena, lhs);
1151 let r = tree_to_expr(arena, rhs);
1152 arena.eq_(l, r)
1153 }
1154 ExprTree::Ne { lhs, rhs } => {
1155 let l = tree_to_expr(arena, lhs);
1156 let r = tree_to_expr(arena, rhs);
1157 arena.ne_(l, r)
1158 }
1159 ExprTree::And { args } => {
1160 let ids: Vec<ExprId> = args.iter().map(|a| tree_to_expr(arena, a)).collect();
1161 arena.and(&ids)
1162 }
1163 ExprTree::Or { args } => {
1164 let ids: Vec<ExprId> = args.iter().map(|a| tree_to_expr(arena, a)).collect();
1165 arena.or(&ids)
1166 }
1167 ExprTree::Not { arg } => {
1168 let x = tree_to_expr(arena, arg);
1169 arena.not(x)
1170 }
1171 ExprTree::Piecewise { pieces } => {
1172 let pairs: smallvec::SmallVec<[(ExprId, ExprId); 3]> = pieces
1173 .iter()
1174 .map(|(val, cond)| (tree_to_expr(arena, val), tree_to_expr(arena, cond)))
1175 .collect();
1176 arena.intern(ExprNode::Piecewise(pairs))
1177 }
1178 ExprTree::EmptySet => arena.intern(ExprNode::EmptySet),
1179 ExprTree::UniversalSet => arena.intern(ExprNode::UniversalSet),
1180 ExprTree::Interval { start, end, flags } => {
1181 let s = tree_to_expr(arena, start);
1182 let e = tree_to_expr(arena, end);
1183 arena.intern(ExprNode::Interval(s, e, *flags))
1184 }
1185 ExprTree::FiniteSet { elements } => {
1186 let ids: smallvec::SmallVec<[ExprId; 4]> =
1187 elements.iter().map(|e| tree_to_expr(arena, e)).collect();
1188 arena.intern(ExprNode::FiniteSet(ids))
1189 }
1190 ExprTree::SetUnion { sets } => {
1191 let ids: smallvec::SmallVec<[ExprId; 4]> =
1192 sets.iter().map(|s| tree_to_expr(arena, s)).collect();
1193 arena.intern(ExprNode::SetUnion(ids))
1194 }
1195 ExprTree::SetIntersection { sets } => {
1196 let ids: smallvec::SmallVec<[ExprId; 4]> =
1197 sets.iter().map(|s| tree_to_expr(arena, s)).collect();
1198 arena.intern(ExprNode::SetIntersection(ids))
1199 }
1200 ExprTree::SetComplement { set, universe } => {
1201 let s = tree_to_expr(arena, set);
1202 let u = tree_to_expr(arena, universe);
1203 arena.intern(ExprNode::SetComplement(s, u))
1204 }
1205 ExprTree::Limit { body, var, point } => {
1206 let b = tree_to_expr(arena, body);
1207 let v = tree_to_expr(arena, var);
1208 let p = tree_to_expr(arena, point);
1209 arena.intern(ExprNode::Limit(b, v, p))
1210 }
1211 ExprTree::Series {
1212 body,
1213 var,
1214 point,
1215 order,
1216 } => {
1217 let b = tree_to_expr(arena, body);
1218 let v = tree_to_expr(arena, var);
1219 let p = tree_to_expr(arena, point);
1220 let o = tree_to_expr(arena, order);
1221 arena.intern(ExprNode::Series(b, v, p, o))
1222 }
1223 ExprTree::LaplaceTransform { body, t, s } => {
1224 let b = tree_to_expr(arena, body);
1225 let ti = tree_to_expr(arena, t);
1226 let si = tree_to_expr(arena, s);
1227 arena.intern(ExprNode::LaplaceTransform(b, ti, si))
1228 }
1229 ExprTree::InverseLaplaceTransform { body, s, t } => {
1230 let b = tree_to_expr(arena, body);
1231 let si = tree_to_expr(arena, s);
1232 let ti = tree_to_expr(arena, t);
1233 arena.intern(ExprNode::InverseLaplaceTransform(b, si, ti))
1234 }
1235 ExprTree::Residue { body, var, point } => {
1236 let b = tree_to_expr(arena, body);
1237 let v = tree_to_expr(arena, var);
1238 let p = tree_to_expr(arena, point);
1239 arena.intern(ExprNode::Residue(b, v, p))
1240 }
1241 ExprTree::RootOf { poly, index } => {
1242 let p = tree_to_expr(arena, poly);
1243 let i = tree_to_expr(arena, index);
1244 arena.intern(ExprNode::RootOf(p, i))
1245 }
1246 ExprTree::DSolve { expr, func, var } => {
1247 let e = tree_to_expr(arena, expr);
1248 let f = tree_to_expr(arena, func);
1249 let v = tree_to_expr(arena, var);
1250 arena.intern(ExprNode::DSolve(e, f, v))
1251 }
1252 ExprTree::RootSum { poly, body, sumvar } => {
1253 let p = tree_to_expr(arena, poly);
1254 let b = tree_to_expr(arena, body);
1255 let s = tree_to_expr(arena, sumvar);
1256 arena.intern(ExprNode::RootSum(p, b, s))
1257 }
1258 ExprTree::ConditionSet { var, condition } => {
1259 let v = tree_to_expr(arena, var);
1260 let c = tree_to_expr(arena, condition);
1261 arena.intern(ExprNode::ConditionSet(v, c))
1262 }
1263 }
1264}
1265
1266impl ExprTree {
1271 fn head_and_children(&self) -> (String, Option<Vec<&ExprTree>>) {
1280 type Parts<'t> = (String, Option<Vec<&'t ExprTree>>);
1281 fn one<'t>(head: &str, a: &'t ExprTree) -> Parts<'t> {
1282 (head.to_string(), Some(vec![a]))
1283 }
1284 fn two<'t>(head: &str, a: &'t ExprTree, b: &'t ExprTree) -> Parts<'t> {
1285 (head.to_string(), Some(vec![a, b]))
1286 }
1287 fn many<'t>(head: &str, items: &'t [ExprTree]) -> Parts<'t> {
1288 (head.to_string(), Some(items.iter().collect()))
1289 }
1290 fn atom<'t>(head: &str) -> Parts<'t> {
1291 (head.to_string(), None)
1292 }
1293 match self {
1294 ExprTree::Num { numer, denom } => {
1295 if denom == "1" {
1296 atom(&format!("Integer({numer})"))
1297 } else {
1298 atom(&format!("Rational({numer}, {denom})"))
1299 }
1300 }
1301 ExprTree::Symbol { name } => atom(&format!("Symbol('{name}')")),
1302 ExprTree::Pi => atom("pi"),
1303 ExprTree::E => atom("E"),
1304 ExprTree::ImaginaryUnit => atom("I"),
1305 ExprTree::EulerGamma => atom("EulerGamma"),
1306 ExprTree::Catalan => atom("Catalan"),
1307 ExprTree::GoldenRatio => atom("GoldenRatio"),
1308 ExprTree::PhysicalConstant { name, value } => {
1309 one(&format!("PhysicalConstant('{name}')"), value)
1310 }
1311 ExprTree::Infinity => atom("oo"),
1312 ExprTree::NegInfinity => atom("-oo"),
1313 ExprTree::ComplexInfinity => atom("zoo"),
1314 ExprTree::NaN => atom("nan"),
1315 ExprTree::Add { terms } => many("Add", terms),
1316 ExprTree::Mul { factors } => many("Mul", factors),
1317 ExprTree::Pow { base, exp } => two("Pow", base, exp),
1318 ExprTree::Neg { inner } => one("Neg", inner),
1319 ExprTree::Sin { arg } => one("sin", arg),
1320 ExprTree::Cos { arg } => one("cos", arg),
1321 ExprTree::Tan { arg } => one("tan", arg),
1322 ExprTree::Exp { arg } => one("exp", arg),
1323 ExprTree::Ln { arg } => one("log", arg),
1324 ExprTree::Sqrt { arg } => one("sqrt", arg),
1325 ExprTree::Abs { arg } => one("Abs", arg),
1326 ExprTree::Asin { arg } => one("asin", arg),
1327 ExprTree::Acos { arg } => one("acos", arg),
1328 ExprTree::Atan { arg } => one("atan", arg),
1329 ExprTree::Atan2 { y, x } => two("atan2", y, x),
1330 ExprTree::Sinh { arg } => one("sinh", arg),
1331 ExprTree::Cosh { arg } => one("cosh", arg),
1332 ExprTree::Tanh { arg } => one("tanh", arg),
1333 ExprTree::Asinh { arg } => one("asinh", arg),
1334 ExprTree::Acosh { arg } => one("acosh", arg),
1335 ExprTree::Atanh { arg } => one("atanh", arg),
1336 ExprTree::Sign { arg } => one("sign", arg),
1337 ExprTree::Heaviside { arg } => one("Heaviside", arg),
1338 ExprTree::DiracDelta { arg } => one("DiracDelta", arg),
1339 ExprTree::Gamma { arg } => one("gamma", arg),
1340 ExprTree::LogGamma { arg } => one("loggamma", arg),
1341 ExprTree::Digamma { arg } => one("digamma", arg),
1342 ExprTree::Erf { arg } => one("erf", arg),
1343 ExprTree::Erfc { arg } => one("erfc", arg),
1344 ExprTree::LambertW { arg } => one("LambertW", arg),
1345 ExprTree::Beta { a, b } => two("beta", a, b),
1346 ExprTree::Re { arg } => one("re", arg),
1347 ExprTree::Im { arg } => one("im", arg),
1348 ExprTree::Conjugate { arg } => one("conjugate", arg),
1349 ExprTree::Arg { arg } => one("arg", arg),
1350 ExprTree::Si { arg } => one("Si", arg),
1351 ExprTree::Ci { arg } => one("Ci", arg),
1352 ExprTree::Ei { arg } => one("Ei", arg),
1353 ExprTree::Li { arg } => one("li", arg),
1354 ExprTree::Zeta { arg } => one("zeta", arg),
1355 ExprTree::Polygamma { n, arg } => two("polygamma", n, arg),
1356 ExprTree::KroneckerDelta { i, j } => two("KroneckerDelta", i, j),
1357 ExprTree::Floor { arg } => one("floor", arg),
1358 ExprTree::Ceiling { arg } => one("ceiling", arg),
1359 ExprTree::Min { args } => many("Min", args),
1360 ExprTree::Max { args } => many("Max", args),
1361 ExprTree::BoolTrue => atom("true"),
1362 ExprTree::BoolFalse => atom("false"),
1363 ExprTree::Gt { lhs, rhs } => two("StrictGreaterThan", lhs, rhs),
1364 ExprTree::Ge { lhs, rhs } => two("GreaterThan", lhs, rhs),
1365 ExprTree::Eq_ { lhs, rhs } => two("Equality", lhs, rhs),
1366 ExprTree::Ne { lhs, rhs } => two("Unequality", lhs, rhs),
1367 ExprTree::And { args } => many("And", args),
1368 ExprTree::Or { args } => many("Or", args),
1369 ExprTree::Not { arg } => one("Not", arg),
1370 ExprTree::Piecewise { pieces } => (
1371 "Piecewise".to_string(),
1372 Some(pieces.iter().flat_map(|(v, c)| [v, c]).collect()),
1373 ),
1374 ExprTree::Apply { name, args } => many(name, args),
1375 ExprTree::Derivative { body, var } => two("Derivative", body, var),
1376 ExprTree::Integral { body, var } => two("Integral", body, var),
1377 ExprTree::DefiniteIntegral {
1378 body,
1379 var,
1380 lower,
1381 upper,
1382 } => (
1383 "DefiniteIntegral".to_string(),
1384 Some(vec![body, var, lower, upper]),
1385 ),
1386 ExprTree::Sum {
1387 body,
1388 var,
1389 lower,
1390 upper,
1391 } => ("Sum".to_string(), Some(vec![body, var, lower, upper])),
1392 ExprTree::Product_ {
1393 body,
1394 var,
1395 lower,
1396 upper,
1397 } => ("Product".to_string(), Some(vec![body, var, lower, upper])),
1398 ExprTree::EmptySet => atom("EmptySet"),
1399 ExprTree::UniversalSet => atom("UniversalSet"),
1400 ExprTree::Interval { start, end, .. } => two("Interval", start, end),
1401 ExprTree::FiniteSet { elements } => many("FiniteSet", elements),
1402 ExprTree::SetUnion { sets } => many("Union", sets),
1403 ExprTree::SetIntersection { sets } => many("Intersection", sets),
1404 ExprTree::SetComplement { set, universe } => two("Complement", set, universe),
1405 ExprTree::Limit { body, var, point } => {
1406 ("Limit".to_string(), Some(vec![body, var, point]))
1407 }
1408 ExprTree::Series {
1409 body,
1410 var,
1411 point,
1412 order,
1413 } => ("Series".to_string(), Some(vec![body, var, point, order])),
1414 ExprTree::LaplaceTransform { body, t, s } => {
1415 ("LaplaceTransform".to_string(), Some(vec![body, t, s]))
1416 }
1417 ExprTree::InverseLaplaceTransform { body, s, t } => (
1418 "InverseLaplaceTransform".to_string(),
1419 Some(vec![body, s, t]),
1420 ),
1421 ExprTree::Residue { body, var, point } => {
1422 ("Residue".to_string(), Some(vec![body, var, point]))
1423 }
1424 ExprTree::RootOf { poly, index } => two("RootOf", poly, index),
1425 ExprTree::DSolve { expr, func, var } => {
1426 ("DSolve".to_string(), Some(vec![expr, func, var]))
1427 }
1428 ExprTree::RootSum { poly, body, sumvar } => {
1429 ("RootSum".to_string(), Some(vec![poly, body, sumvar]))
1430 }
1431 ExprTree::ConditionSet { var, condition } => two("ConditionSet", var, condition),
1432 }
1433 }
1434
1435 fn srepr_trailing(&self) -> Option<String> {
1438 match self {
1439 ExprTree::Interval { flags, .. } => {
1440 Some(format!(", {}, {}", flags & 0x01 != 0, flags & 0x02 != 0))
1441 }
1442 _ => None,
1443 }
1444 }
1445
1446 #[must_use]
1459 pub fn to_srepr(&self) -> String {
1460 enum Item<'t> {
1461 Text(String),
1462 Node(&'t ExprTree),
1463 }
1464 let mut out = String::new();
1465 let mut stack: Vec<Item<'_>> = vec![Item::Node(self)];
1466 while let Some(item) = stack.pop() {
1467 match item {
1468 Item::Text(s) => out.push_str(&s),
1469 Item::Node(node) => {
1470 let (head, children) = node.head_and_children();
1471 out.push_str(&head);
1472 let Some(children) = children else { continue };
1473 out.push('(');
1474 let mut close = String::new();
1476 if let Some(trailing) = node.srepr_trailing() {
1477 close.push_str(&trailing);
1478 }
1479 close.push(')');
1480 stack.push(Item::Text(close));
1481 let pairwise = matches!(node, ExprTree::Piecewise { .. });
1482 for (i, child) in children.iter().enumerate().rev() {
1483 if pairwise {
1484 if i % 2 == 1 {
1486 stack.push(Item::Text(")".into()));
1487 stack.push(Item::Node(child));
1488 stack.push(Item::Text(", ".into()));
1489 } else {
1490 stack.push(Item::Node(child));
1491 stack.push(Item::Text(if i == 0 { "(" } else { ", (" }.into()));
1492 }
1493 } else {
1494 stack.push(Item::Node(child));
1495 if i > 0 {
1496 stack.push(Item::Text(", ".into()));
1497 }
1498 }
1499 }
1500 }
1501 }
1502 }
1503 out
1504 }
1505
1506 #[must_use]
1513 pub fn to_dot(&self) -> String {
1514 let mut nodes: Vec<String> = Vec::new();
1515 let mut edges: Vec<String> = Vec::new();
1516 let mut stack: Vec<(&ExprTree, Option<usize>)> = vec![(self, None)];
1518 while let Some((node, parent)) = stack.pop() {
1519 let id = nodes.len();
1520 let (head, children) = node.head_and_children();
1521 let label = match node {
1522 ExprTree::Interval { flags, .. } => format!(
1523 "Interval('{}{}')",
1524 if flags & 0x01 != 0 { '(' } else { '[' },
1525 if flags & 0x02 != 0 { ')' } else { ']' }
1526 ),
1527 _ => head,
1528 };
1529 nodes.push(format!(
1530 " n{id} [label=\"{}\"];",
1531 label.replace('\\', "\\\\").replace('"', "\\\"")
1532 ));
1533 if let Some(p) = parent {
1534 edges.push(format!(" n{p} -> n{id};"));
1535 }
1536 if let Some(children) = children {
1537 for child in children.into_iter().rev() {
1538 stack.push((child, Some(id)));
1539 }
1540 }
1541 }
1542 let mut out = String::from("digraph {\n ordering=out;\n rankdir=TD;\n");
1543 for n in &nodes {
1544 out.push_str(n);
1545 out.push('\n');
1546 }
1547 for e in &edges {
1548 out.push_str(e);
1549 out.push('\n');
1550 }
1551 out.push_str("}\n");
1552 out
1553 }
1554}
1555
1556impl<S: crate::api::expr::Sort> crate::api::expr::Expr<S> {
1557 #[must_use = "returns the rendered string; does not modify in place"]
1581 pub fn to_srepr(&self) -> String {
1582 self.to_tree().to_srepr()
1583 }
1584
1585 #[must_use = "returns the rendered string; does not modify in place"]
1615 pub fn to_dot(&self) -> String {
1616 self.to_tree().to_dot()
1617 }
1618}
1619
1620#[cfg(test)]
1625mod tests {
1626 use super::*;
1627 use crate::base::arena::Arena;
1628
1629 fn display(a: &Arena, id: ExprId) -> String {
1630 a.display(id).to_string()
1631 }
1632
1633 #[test]
1634 fn roundtrip_integer() {
1635 let mut a = Arena::new();
1636 let expr = a.int(42);
1637 let tree = expr_to_tree(&a, expr);
1638 let back = tree_to_expr(&mut a, &tree);
1639 assert_eq!(display(&a, back), "42");
1640 }
1641
1642 #[test]
1643 fn roundtrip_rational() {
1644 let mut a = Arena::new();
1645 let expr = a.rational(3, 7);
1646 let tree = expr_to_tree(&a, expr);
1647 let back = tree_to_expr(&mut a, &tree);
1648 assert_eq!(display(&a, back), "3/7");
1649 }
1650
1651 #[test]
1652 fn roundtrip_symbol() {
1653 let mut a = Arena::new();
1654 let expr = a.symbol("x");
1655 let tree = expr_to_tree(&a, expr);
1656 let back = tree_to_expr(&mut a, &tree);
1657 assert_eq!(display(&a, back), "x");
1658 }
1659
1660 #[test]
1661 fn roundtrip_polynomial() {
1662 let mut a = Arena::new();
1663 let x = a.symbol("x");
1664 let two = a.int(2);
1665 let x2 = a.pow(x, two);
1666 let two_id = a.int(2);
1667 let two_x = a.mul(&[two_id, x]);
1668 let one = a.one;
1669 let expr = a.add(&[x2, two_x, one]);
1670 let tree = expr_to_tree(&a, expr);
1671 let back = tree_to_expr(&mut a, &tree);
1672 assert_eq!(display(&a, expr), display(&a, back));
1673 }
1674
1675 #[test]
1676 fn roundtrip_sin() {
1677 let mut a = Arena::new();
1678 let x = a.symbol("x");
1679 let expr = a.sin(x);
1680 let tree = expr_to_tree(&a, expr);
1681 let back = tree_to_expr(&mut a, &tree);
1682 assert_eq!(display(&a, back), "sin(x)");
1683 }
1684
1685 #[test]
1686 fn roundtrip_pi() {
1687 let a = Arena::new();
1688 let tree = expr_to_tree(&a, a.pi);
1689 let mut a2 = Arena::new();
1690 let back = tree_to_expr(&mut a2, &tree);
1691 assert_eq!(display(&a2, back), "pi");
1692 }
1693
1694 #[test]
1695 fn json_roundtrip() {
1696 let mut a = Arena::new();
1697 let x = a.symbol("x");
1698 let two = a.int(2);
1699 let expr = a.pow(x, two);
1700 let tree = expr_to_tree(&a, expr);
1701 let json = serde_json::to_string(&tree).unwrap();
1702 let tree2: ExprTree = serde_json::from_str(&json).unwrap();
1703 assert_eq!(tree, tree2);
1704 let back = tree_to_expr(&mut a, &tree2);
1705 assert_eq!(display(&a, back), "x^2");
1706 }
1707
1708 #[test]
1709 fn json_deserialize_from_scratch() {
1710 let json = r#"{"type":"Add","terms":[{"type":"Num","numer":"1","denom":"1"},{"type":"Symbol","name":"x"}]}"#;
1712 let tree: ExprTree = serde_json::from_str(json).unwrap();
1713 let mut a = Arena::new();
1714 let expr = tree_to_expr(&mut a, &tree);
1715 assert_eq!(display(&a, expr), "x + 1");
1716 }
1717
1718 #[test]
1719 fn roundtrip_all_functions() {
1720 let mut a = Arena::new();
1721 let x = a.symbol("x");
1722 let funcs = [
1723 a.sin(x),
1724 a.cos(x),
1725 a.tan(x),
1726 a.exp(x),
1727 a.ln(x),
1728 a.sqrt(x),
1729 a.abs(x),
1730 a.asin(x),
1731 a.acos(x),
1732 a.atan(x),
1733 a.sinh(x),
1734 a.cosh(x),
1735 a.tanh(x),
1736 ];
1737 for &expr in &funcs {
1738 let tree = expr_to_tree(&a, expr);
1739 let back = tree_to_expr(&mut a, &tree);
1740 assert_eq!(
1741 display(&a, expr),
1742 display(&a, back),
1743 "roundtrip failed for {}",
1744 display(&a, expr)
1745 );
1746 }
1747 }
1748
1749 #[test]
1750 fn roundtrip_derivative() {
1751 let mut a = Arena::new();
1752 let x = a.symbol("x");
1753 let body = a.sin(x);
1754 let expr = a.intern(ExprNode::Derivative(body, x));
1755 let tree = expr_to_tree(&a, expr);
1756 let back = tree_to_expr(&mut a, &tree);
1757 assert_eq!(display(&a, back), "Derivative(sin(x), x)");
1758 }
1759
1760 #[test]
1761 fn roundtrip_integral() {
1762 let mut a = Arena::new();
1763 let x = a.symbol("x");
1764 let body = a.sin(x);
1765 let expr = a.intern(ExprNode::Integral(body, x));
1766 let tree = expr_to_tree(&a, expr);
1767 let back = tree_to_expr(&mut a, &tree);
1768 assert_eq!(display(&a, back), "Integral(sin(x), x)");
1769 }
1770
1771 #[test]
1772 fn roundtrip_definite_integral() {
1773 let mut a = Arena::new();
1774 let x = a.symbol("x");
1775 let body = a.pow(x, x);
1776 let one = a.one;
1777 let expr = a.definite_integral(body, x, a.zero, one);
1778 let tree = expr_to_tree(&a, expr);
1779 let json = serde_json::to_string(&tree).unwrap();
1780 let tree2: ExprTree = serde_json::from_str(&json).unwrap();
1781 assert_eq!(tree2, tree);
1782 assert_eq!(tree_to_expr(&mut a, &tree2), expr);
1783 assert_eq!(display(&a, expr), "Integral(x^x, x, 0, 1)");
1784 }
1785
1786 #[test]
1789 fn roundtrip_named_constants() {
1790 let mut a = Arena::new();
1791 for id in [a.euler_gamma, a.catalan, a.golden_ratio] {
1792 let tree = expr_to_tree(&a, id);
1793 let json = serde_json::to_string(&tree).unwrap();
1794 let tree2: ExprTree = serde_json::from_str(&json).unwrap();
1795 assert_eq!(tree2, tree);
1796 assert_eq!(tree_to_expr(&mut a, &tree2), id);
1797 }
1798 assert_eq!(expr_to_tree(&a, a.euler_gamma), ExprTree::EulerGamma);
1799 assert_eq!(expr_to_tree(&a, a.catalan), ExprTree::Catalan);
1800 assert_eq!(expr_to_tree(&a, a.golden_ratio), ExprTree::GoldenRatio);
1801 }
1802
1803 #[test]
1804 fn roundtrip_complex_and_special_nodes() {
1805 let mut a = Arena::new();
1806 let x = a.symbol("x");
1807 let n = a.symbol("n");
1808 let nodes = [
1809 a.intern(ExprNode::Re(x)),
1810 a.intern(ExprNode::Im(x)),
1811 a.intern(ExprNode::Conjugate(x)),
1812 a.intern(ExprNode::Arg(x)),
1813 a.intern(ExprNode::Si(x)),
1814 a.intern(ExprNode::Ci(x)),
1815 a.intern(ExprNode::Ei(x)),
1816 a.intern(ExprNode::Li(x)),
1817 a.intern(ExprNode::Zeta(x)),
1818 a.intern(ExprNode::Polygamma(n, x)),
1819 a.intern(ExprNode::KroneckerDelta(n, x)),
1820 ];
1821 for id in nodes {
1822 let tree = expr_to_tree(&a, id);
1823 let json = serde_json::to_string(&tree).unwrap();
1824 let tree2: ExprTree = serde_json::from_str(&json).unwrap();
1825 let back = tree_to_expr(&mut a, &tree2);
1826 assert_eq!(back, id, "round trip of {}", display(&a, id));
1827 }
1828 }
1829
1830 #[test]
1831 fn tree_to_expr_uses_canonical_constructors() {
1832 let mut a = Arena::new();
1834 let two = a.int(2);
1835 let tree = ExprTree::Zeta {
1836 arg: Box::new(expr_to_tree(&a, two)),
1837 };
1838 let id = tree_to_expr(&mut a, &tree);
1839 assert_eq!(display(&a, id), "1/6*pi^2");
1840 }
1841}