1use crate::symbol::{NumType, Seft, Symbol};
6use smallvec::SmallVec;
7use std::fmt;
8
9pub const MAX_EXPR_LEN: usize = 21;
11
12#[derive(Debug, Clone, Copy, Default)]
14pub enum OutputFormat {
15 #[default]
17 Default,
18 Pretty,
20 Mathematica,
22 SymPy,
24}
25
26impl OutputFormat {
27 #[allow(dead_code)]
29 pub fn symbol_name(&self, sym: Symbol) -> &'static str {
30 use Symbol::*;
31 match self {
32 OutputFormat::Default => sym.name(),
33 OutputFormat::Pretty => match sym {
34 Pi => "π",
35 E => "ℯ",
36 Phi => "φ",
37 Sqrt => "√",
38 Square => "²",
39 Gamma => "γ",
40 Plastic => "ρ",
41 Catalan => "G",
42 _ => sym.name(),
43 },
44 OutputFormat::Mathematica => match sym {
45 Pi => "Pi",
46 E => "E",
47 Phi => "GoldenRatio",
48 Sqrt => "Sqrt",
49 Square => "²",
50 Ln => "Log",
51 Exp => "Exp",
52 SinPi => "Sin[Pi*",
53 CosPi => "Cos[Pi*",
54 TanPi => "Tan[Pi*",
55 LambertW => "ProductLog",
56 Gamma => "EulerGamma",
57 _ => sym.name(),
58 },
59 OutputFormat::SymPy => match sym {
60 Pi => "pi",
61 E => "E",
62 Phi => "GoldenRatio",
63 Sqrt => "sqrt",
64 Square => "²",
65 Ln => "log",
66 Exp => "exp",
67 SinPi => "sin(pi*",
68 CosPi => "cos(pi*",
69 TanPi => "tan(pi*",
70 LambertW => "lambertw",
71 Gamma => "EulerGamma",
72 _ => sym.name(),
73 },
74 }
75 }
76}
77
78#[derive(Clone, PartialEq, Eq, Hash)]
80pub struct Expression {
81 symbols: SmallVec<[Symbol; MAX_EXPR_LEN]>,
83 complexity: u32,
85 contains_x: bool,
87}
88
89impl Expression {
90 pub fn new() -> Self {
92 Self {
93 symbols: SmallVec::new(),
94 complexity: 0,
95 contains_x: false,
96 }
97 }
98
99 #[cfg(test)]
101 pub fn from_symbols(symbols: &[Symbol]) -> Self {
102 let complexity: u32 = symbols
104 .iter()
105 .map(|s| s.weight())
106 .fold(0u32, |acc, w| acc.saturating_add(w));
107 let contains_x = symbols.contains(&Symbol::X);
108 Self {
109 symbols: SmallVec::from_slice(symbols),
110 complexity,
111 contains_x,
112 }
113 }
114
115 pub fn parse(s: &str) -> Option<Self> {
121 let mut symbols = SmallVec::new();
122 for b in s.bytes() {
123 symbols.push(Symbol::from_byte(b)?);
124 }
125 if !Self::is_valid_postfix(&symbols) {
126 return None;
127 }
128 let complexity: u32 = symbols
130 .iter()
131 .map(|s: &Symbol| s.weight())
132 .fold(0u32, |acc, w| acc.saturating_add(w));
133 let contains_x = symbols.contains(&Symbol::X);
134 Some(Self {
135 symbols,
136 complexity,
137 contains_x,
138 })
139 }
140
141 #[inline]
143 pub fn symbols(&self) -> &[Symbol] {
144 &self.symbols
145 }
146
147 #[inline]
149 pub fn len(&self) -> usize {
150 self.symbols.len()
151 }
152
153 #[inline]
155 pub fn is_empty(&self) -> bool {
156 self.symbols.is_empty()
157 }
158
159 #[inline]
161 pub fn complexity(&self) -> u32 {
162 self.complexity
163 }
164
165 #[inline]
167 pub fn contains_x(&self) -> bool {
168 self.contains_x
169 }
170
171 #[inline]
173 pub fn count_symbol(&self, sym: Symbol) -> u32 {
174 self.symbols.iter().filter(|&&s| s == sym).count() as u32
175 }
176
177 #[allow(dead_code)]
182 pub fn is_valid(&self) -> bool {
183 Self::is_valid_postfix(&self.symbols)
184 }
185
186 fn is_valid_postfix(symbols: &[Symbol]) -> bool {
187 let mut depth: i32 = 0;
188 for sym in symbols {
189 match sym.seft() {
190 Seft::A => depth += 1,
191 Seft::B => { }
192 Seft::C => depth -= 1, }
194 if depth < 1 {
195 return false; }
197 }
198 depth == 1
199 }
200
201 pub fn push(&mut self, sym: Symbol) {
203 self.complexity = self.complexity.saturating_add(sym.weight());
205 if sym == Symbol::X {
206 self.contains_x = true;
207 }
208 self.symbols.push(sym);
209 }
210
211 pub fn pop(&mut self) -> Option<Symbol> {
213 let sym = self.symbols.pop()?;
214 self.complexity = self.complexity.saturating_sub(sym.weight());
216 if sym == Symbol::X {
218 self.contains_x = self.symbols.contains(&Symbol::X);
219 }
220 Some(sym)
221 }
222
223 pub fn push_with_table(&mut self, sym: Symbol, table: &crate::symbol_table::SymbolTable) {
228 self.complexity = self.complexity.saturating_add(table.weight(sym));
230 if sym == Symbol::X {
231 self.contains_x = true;
232 }
233 self.symbols.push(sym);
234 }
235
236 pub fn pop_with_table(&mut self, table: &crate::symbol_table::SymbolTable) -> Option<Symbol> {
241 let sym = self.symbols.pop()?;
242 self.complexity = self.complexity.saturating_sub(table.weight(sym));
244 if sym == Symbol::X {
246 self.contains_x = self.symbols.contains(&Symbol::X);
247 }
248 Some(sym)
249 }
250
251 pub fn to_postfix(&self) -> String {
253 self.symbols.iter().map(|s| *s as u8 as char).collect()
254 }
255
256 pub fn to_infix(&self) -> String {
268 const PREC_ATOM: u8 = 100; const PREC_POWER: u8 = 9; const PREC_UNARY: u8 = 8; const PREC_MUL: u8 = 6; const PREC_ADD: u8 = 4; fn needs_paren(
281 parent_prec: u8,
282 child_prec: u8,
283 is_right_assoc: bool,
284 is_right_operand: bool,
285 ) -> bool {
286 if child_prec < parent_prec {
287 return true;
288 }
289 if is_right_assoc && is_right_operand && child_prec == parent_prec {
292 return true;
293 }
294 false
295 }
296
297 fn maybe_paren_prec(
299 s: &str,
300 prec: u8,
301 parent_prec: u8,
302 is_right_assoc: bool,
303 is_right: bool,
304 ) -> String {
305 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
306 format!("({})", s)
307 } else {
308 s.to_string()
309 }
310 }
311
312 let mut stack: Vec<(String, u8)> = Vec::new(); for &sym in &self.symbols {
315 match sym.seft() {
316 Seft::A => {
317 stack.push((sym.display_name(), PREC_ATOM));
318 }
319 Seft::B => {
320 let (arg, arg_prec) = stack
321 .pop()
322 .expect("stack underflow in to_infix: expression is not valid postfix");
323 let result = match sym {
324 Symbol::Neg => {
325 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_UNARY, false, false);
327 format!("-{}", arg_s)
328 }
329 Symbol::Recip => {
330 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_MUL, false, false);
331 format!("1/{}", arg_s)
332 }
333 Symbol::Sqrt => format!("sqrt({})", arg),
334 Symbol::Square => {
335 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, false, false);
336 format!("{}^2", arg_s)
337 }
338 Symbol::Ln => format!("ln({})", arg),
339 Symbol::Exp => {
340 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, true, true);
341 format!("e^{}", arg_s)
342 }
343 Symbol::SinPi => format!("sinpi({})", arg),
344 Symbol::CosPi => format!("cospi({})", arg),
345 Symbol::TanPi => format!("tanpi({})", arg),
346 Symbol::LambertW => format!("W({})", arg),
347 Symbol::UserFunction0
348 | Symbol::UserFunction1
349 | Symbol::UserFunction2
350 | Symbol::UserFunction3
351 | Symbol::UserFunction4
352 | Symbol::UserFunction5
353 | Symbol::UserFunction6
354 | Symbol::UserFunction7
355 | Symbol::UserFunction8
356 | Symbol::UserFunction9
357 | Symbol::UserFunction10
358 | Symbol::UserFunction11
359 | Symbol::UserFunction12
360 | Symbol::UserFunction13
361 | Symbol::UserFunction14
362 | Symbol::UserFunction15 => format!("{}({})", sym.display_name(), arg),
363 _ => "?".to_string(),
364 };
365 stack.push((result, PREC_ATOM)); }
367 Seft::C => {
368 let (b, b_prec) = stack
369 .pop()
370 .expect("stack underflow in to_infix: expression is not valid postfix");
371 let (a, a_prec) = stack
372 .pop()
373 .expect("stack underflow in to_infix: expression is not valid postfix");
374 let (result, prec) = match sym {
375 Symbol::Add => {
376 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
379 (format!("{}+{}", a, b_s), PREC_ADD)
380 }
381 Symbol::Sub => {
382 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
384 (format!("{}-{}", a, b_s), PREC_ADD)
385 }
386 Symbol::Mul => {
387 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
388 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL, false, true);
389 if a_s.chars().last().is_some_and(|c| c.is_ascii_digit())
391 && b_s.chars().next().is_some_and(|c| c.is_alphabetic())
392 {
393 (format!("{} {}", a_s, b_s), PREC_MUL)
394 } else {
395 (format!("{}*{}", a_s, b_s), PREC_MUL)
396 }
397 }
398 Symbol::Div => {
399 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
400 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL + 1, false, true);
401 (format!("{}/{}", a_s, b_s), PREC_MUL)
402 }
403 Symbol::Pow => {
404 let a_s = maybe_paren_prec(&a, a_prec, PREC_POWER, true, false);
407 let b_s = maybe_paren_prec(&b, b_prec, PREC_POWER, true, true);
409 (format!("{}^{}", a_s, b_s), PREC_POWER)
410 }
411 Symbol::Root => (format!("{}\"/{}", a, b), PREC_POWER),
412 Symbol::Log => (format!("log_{}({})", a, b), PREC_ATOM),
413 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
414 _ => unreachable!(),
415 };
416 stack.push((result, prec));
417 }
418 }
419 }
420
421 stack.pop().map(|(s, _)| s).unwrap_or_else(|| "?".into())
422 }
423
424 pub fn to_infix_with_table(&self, table: &crate::symbol_table::SymbolTable) -> String {
429 const PREC_ATOM: u8 = 100; const PREC_POWER: u8 = 9; const PREC_UNARY: u8 = 8; const PREC_MUL: u8 = 6; const PREC_ADD: u8 = 4; fn needs_paren(
438 parent_prec: u8,
439 child_prec: u8,
440 is_right_assoc: bool,
441 is_right_operand: bool,
442 ) -> bool {
443 if child_prec < parent_prec {
444 return true;
445 }
446 if is_right_assoc && is_right_operand && child_prec == parent_prec {
447 return true;
448 }
449 false
450 }
451
452 fn maybe_paren_prec(
454 s: &str,
455 prec: u8,
456 parent_prec: u8,
457 is_right_assoc: bool,
458 is_right: bool,
459 ) -> String {
460 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
461 format!("({})", s)
462 } else {
463 s.to_string()
464 }
465 }
466
467 let mut stack: Vec<(String, u8)> = Vec::new();
468
469 for &sym in &self.symbols {
470 match sym.seft() {
471 Seft::A => {
472 stack.push((table.name(sym).to_string(), PREC_ATOM));
473 }
474 Seft::B => {
475 let (arg, arg_prec) = stack
476 .pop()
477 .expect("stack underflow in to_infix: expression is not valid postfix");
478 let result = match sym {
479 Symbol::Neg => {
480 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_UNARY, false, false);
481 format!("-{}", arg_s)
482 }
483 Symbol::Recip => {
484 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_MUL, false, false);
485 format!("1/{}", arg_s)
486 }
487 Symbol::Sqrt => format!("sqrt({})", arg),
488 Symbol::Square => {
489 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, false, false);
490 format!("{}^2", arg_s)
491 }
492 Symbol::Ln => format!("ln({})", arg),
493 Symbol::Exp => {
494 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, true, true);
495 format!("e^{}", arg_s)
496 }
497 Symbol::SinPi => format!("sinpi({})", arg),
498 Symbol::CosPi => format!("cospi({})", arg),
499 Symbol::TanPi => format!("tanpi({})", arg),
500 Symbol::LambertW => format!("W({})", arg),
501 Symbol::UserFunction0
502 | Symbol::UserFunction1
503 | Symbol::UserFunction2
504 | Symbol::UserFunction3
505 | Symbol::UserFunction4
506 | Symbol::UserFunction5
507 | Symbol::UserFunction6
508 | Symbol::UserFunction7
509 | Symbol::UserFunction8
510 | Symbol::UserFunction9
511 | Symbol::UserFunction10
512 | Symbol::UserFunction11
513 | Symbol::UserFunction12
514 | Symbol::UserFunction13
515 | Symbol::UserFunction14
516 | Symbol::UserFunction15 => format!("{}({})", table.name(sym), arg),
517 _ => "?".to_string(),
518 };
519 stack.push((result, PREC_ATOM));
520 }
521 Seft::C => {
522 let (b, b_prec) = stack
523 .pop()
524 .expect("stack underflow in to_infix: expression is not valid postfix");
525 let (a, a_prec) = stack
526 .pop()
527 .expect("stack underflow in to_infix: expression is not valid postfix");
528 let (result, prec) = match sym {
529 Symbol::Add => {
530 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
531 (format!("{}+{}", a, b_s), PREC_ADD)
532 }
533 Symbol::Sub => {
534 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
535 (format!("{}-{}", a, b_s), PREC_ADD)
536 }
537 Symbol::Mul => {
538 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
539 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL, false, true);
540 if a_s.chars().last().is_some_and(|c| c.is_ascii_digit())
541 && b_s.chars().next().is_some_and(|c| c.is_alphabetic())
542 {
543 (format!("{} {}", a_s, b_s), PREC_MUL)
544 } else {
545 (format!("{}*{}", a_s, b_s), PREC_MUL)
546 }
547 }
548 Symbol::Div => {
549 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
550 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL + 1, false, true);
551 (format!("{}/{}", a_s, b_s), PREC_MUL)
552 }
553 Symbol::Pow => {
554 let a_s = maybe_paren_prec(&a, a_prec, PREC_POWER, true, false);
555 let b_s = maybe_paren_prec(&b, b_prec, PREC_POWER, true, true);
556 (format!("{}^{}", a_s, b_s), PREC_POWER)
557 }
558 Symbol::Root => (format!("{}\"/{}", a, b), PREC_POWER),
559 Symbol::Log => (format!("log_{}({})", a, b), PREC_ATOM),
560 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
561 _ => unreachable!(),
562 };
563 stack.push((result, prec));
564 }
565 }
566 }
567
568 stack.pop().map(|(s, _)| s).unwrap_or_else(|| "?".into())
569 }
570
571 pub fn to_infix_with_format(&self, format: OutputFormat) -> String {
573 match format {
574 OutputFormat::Default => self.to_infix(),
575 OutputFormat::Pretty => {
576 let mut result = self.to_infix();
577 result = result.replace("pi", "π");
579 result = result.replace("sqrt(", "√(");
580 result = result.replace("^2", "²");
581 result
582 }
583 OutputFormat::Mathematica => self.to_infix_mathematica(),
584 OutputFormat::SymPy => self.to_infix_sympy(),
585 }
586 }
587
588 pub fn operator_count(&self) -> usize {
590 self.symbols
591 .iter()
592 .filter(|sym| sym.seft() != Seft::A)
593 .count()
594 }
595
596 pub fn tree_depth(&self) -> usize {
598 let mut stack: Vec<usize> = Vec::with_capacity(self.len());
599 for &sym in &self.symbols {
600 match sym.seft() {
601 Seft::A => stack.push(1),
602 Seft::B => {
603 let Some(arg_depth) = stack.pop() else {
604 return 0;
605 };
606 stack.push(arg_depth.saturating_add(1));
607 }
608 Seft::C => {
609 let Some(rhs_depth) = stack.pop() else {
610 return 0;
611 };
612 let Some(lhs_depth) = stack.pop() else {
613 return 0;
614 };
615 stack.push(lhs_depth.max(rhs_depth).saturating_add(1));
616 }
617 }
618 }
619 if stack.len() == 1 {
620 stack[0]
621 } else {
622 0
623 }
624 }
625
626 fn to_infix_mathematica(&self) -> String {
627 let mut stack: Vec<String> = Vec::new();
628
629 for &sym in &self.symbols {
630 match sym.seft() {
631 Seft::A => {
632 let s = match sym {
633 Symbol::Pi => "Pi".to_string(),
634 Symbol::E => "E".to_string(),
635 Symbol::Phi => "GoldenRatio".to_string(),
636 Symbol::Gamma => "EulerGamma".to_string(),
637 _ => sym.display_name(),
638 };
639 stack.push(s);
640 }
641 Seft::B => {
642 let arg = stack
643 .pop()
644 .expect("stack underflow in to_infix: expression is not valid postfix");
645 let s = match sym {
646 Symbol::Neg => format!("-({})", arg),
647 Symbol::Recip => format!("1/({})", arg),
648 Symbol::Sqrt => format!("Sqrt[{}]", arg),
649 Symbol::Square => format!("({})^2", arg),
650 Symbol::Ln => format!("Log[{}]", arg),
651 Symbol::Exp => format!("Exp[{}]", arg),
652 Symbol::SinPi => format!("Sin[Pi*({})]", arg),
653 Symbol::CosPi => format!("Cos[Pi*({})]", arg),
654 Symbol::TanPi => format!("Tan[Pi*({})]", arg),
655 Symbol::LambertW => format!("ProductLog[{}]", arg),
656 Symbol::UserFunction0
657 | Symbol::UserFunction1
658 | Symbol::UserFunction2
659 | Symbol::UserFunction3
660 | Symbol::UserFunction4
661 | Symbol::UserFunction5
662 | Symbol::UserFunction6
663 | Symbol::UserFunction7
664 | Symbol::UserFunction8
665 | Symbol::UserFunction9
666 | Symbol::UserFunction10
667 | Symbol::UserFunction11
668 | Symbol::UserFunction12
669 | Symbol::UserFunction13
670 | Symbol::UserFunction14
671 | Symbol::UserFunction15 => format!("{}[{}]", sym.display_name(), arg),
672 _ => "?".to_string(),
673 };
674 stack.push(s);
675 }
676 Seft::C => {
677 let b = stack
678 .pop()
679 .expect("stack underflow in to_infix: expression is not valid postfix");
680 let a = stack
681 .pop()
682 .expect("stack underflow in to_infix: expression is not valid postfix");
683 let s = match sym {
684 Symbol::Add => format!("({})+({})", a, b),
685 Symbol::Sub => format!("({})-({})", a, b),
686 Symbol::Mul => format!("({})*({})", a, b),
687 Symbol::Div => format!("({})/({})", a, b),
688 Symbol::Pow => format!("({})^({})", a, b),
689 Symbol::Root => format!("({})^(1/({}))", b, a),
690 Symbol::Log => format!("Log[{}, {}]", a, b),
691 Symbol::Atan2 => format!("ArcTan[{}, {}]", b, a),
692 _ => "?".to_string(),
693 };
694 stack.push(s);
695 }
696 }
697 }
698
699 stack.pop().unwrap_or_else(|| "?".to_string())
700 }
701
702 fn to_infix_sympy(&self) -> String {
703 let mut stack: Vec<String> = Vec::new();
704
705 for &sym in &self.symbols {
706 match sym.seft() {
707 Seft::A => {
708 let s = match sym {
709 Symbol::Pi => "pi".to_string(),
710 Symbol::E => "E".to_string(),
711 Symbol::Phi => "GoldenRatio".to_string(),
712 Symbol::Gamma => "EulerGamma".to_string(),
713 _ => sym.display_name(),
714 };
715 stack.push(s);
716 }
717 Seft::B => {
718 let arg = stack
719 .pop()
720 .expect("stack underflow in to_infix: expression is not valid postfix");
721 let s = match sym {
722 Symbol::Neg => format!("-({})", arg),
723 Symbol::Recip => format!("1/({})", arg),
724 Symbol::Sqrt => format!("sqrt({})", arg),
725 Symbol::Square => format!("({})**2", arg),
726 Symbol::Ln => format!("log({})", arg),
727 Symbol::Exp => format!("exp({})", arg),
728 Symbol::SinPi => format!("sin(pi*({}))", arg),
729 Symbol::CosPi => format!("cos(pi*({}))", arg),
730 Symbol::TanPi => format!("tan(pi*({}))", arg),
731 Symbol::LambertW => format!("lambertw({})", arg),
732 Symbol::UserFunction0
733 | Symbol::UserFunction1
734 | Symbol::UserFunction2
735 | Symbol::UserFunction3
736 | Symbol::UserFunction4
737 | Symbol::UserFunction5
738 | Symbol::UserFunction6
739 | Symbol::UserFunction7
740 | Symbol::UserFunction8
741 | Symbol::UserFunction9
742 | Symbol::UserFunction10
743 | Symbol::UserFunction11
744 | Symbol::UserFunction12
745 | Symbol::UserFunction13
746 | Symbol::UserFunction14
747 | Symbol::UserFunction15 => format!("{}({})", sym.display_name(), arg),
748 _ => "?".to_string(),
749 };
750 stack.push(s);
751 }
752 Seft::C => {
753 let b = stack
754 .pop()
755 .expect("stack underflow in to_infix: expression is not valid postfix");
756 let a = stack
757 .pop()
758 .expect("stack underflow in to_infix: expression is not valid postfix");
759 let s = match sym {
760 Symbol::Add => format!("({})+({})", a, b),
761 Symbol::Sub => format!("({})-({})", a, b),
762 Symbol::Mul => format!("({})*({})", a, b),
763 Symbol::Div => format!("({})/({})", a, b),
764 Symbol::Pow => format!("({})**({})", a, b),
765 Symbol::Root => format!("({})**(1/({}))", b, a),
766 Symbol::Log => format!("log({}, {})", b, a),
767 Symbol::Atan2 => format!("atan2({}, {})", a, b),
768 _ => "?".to_string(),
769 };
770 stack.push(s);
771 }
772 }
773 }
774
775 stack.pop().unwrap_or_else(|| "?".to_string())
776 }
777}
778
779impl Default for Expression {
780 fn default() -> Self {
781 Self::new()
782 }
783}
784
785impl fmt::Display for Expression {
786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787 write!(f, "{}", self.to_infix())
788 }
789}
790
791impl fmt::Debug for Expression {
792 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
793 write!(f, "Expr[{}] = {}", self.to_postfix(), self.to_infix())
794 }
795}
796
797#[derive(Clone, Debug)]
799pub struct EvaluatedExpr {
800 pub expr: Expression,
802 pub value: f64,
804 pub derivative: f64,
806 #[allow(dead_code)]
811 pub num_type: NumType,
812}
813
814impl EvaluatedExpr {
815 pub fn new(expr: Expression, value: f64, derivative: f64, num_type: NumType) -> Self {
816 Self {
817 expr,
818 value,
819 derivative,
820 num_type,
821 }
822 }
823}
824
825#[cfg(test)]
826mod tests {
827 use super::*;
828
829 #[test]
830 fn test_parse_expression() {
831 let expr = Expression::parse("32+").unwrap();
832 assert_eq!(expr.len(), 3);
833 assert_eq!(expr.to_postfix(), "32+");
834 assert!(!expr.contains_x());
835 }
836
837 #[test]
838 fn test_expression_validity() {
839 assert!(Expression::parse("32+").unwrap().is_valid());
841
842 assert!(Expression::parse("xs").unwrap().is_valid());
844
845 assert!(Expression::parse("3+").is_none());
847
848 assert!(Expression::parse("32").is_none());
850 }
851
852 #[test]
853 fn test_infix_conversion() {
854 assert_eq!(Expression::parse("32+").unwrap().to_infix(), "3+2");
855 assert_eq!(Expression::parse("32*").unwrap().to_infix(), "3*2");
856 assert_eq!(Expression::parse("xs").unwrap().to_infix(), "x^2");
857 assert_eq!(Expression::parse("xq").unwrap().to_infix(), "sqrt(x)");
858 assert_eq!(Expression::parse("32+5*").unwrap().to_infix(), "(3+2)*5");
859 }
860
861 #[test]
862 fn test_complexity() {
863 let expr = Expression::parse("xs").unwrap(); assert_eq!(expr.complexity(), 15 + 9);
866 }
867
868 #[test]
869 fn test_tree_depth_atom() {
870 assert_eq!(Expression::parse("x").unwrap().tree_depth(), 1);
872 assert_eq!(Expression::parse("1").unwrap().tree_depth(), 1);
873 assert_eq!(Expression::parse("p").unwrap().tree_depth(), 1); }
875
876 #[test]
877 fn test_tree_depth_unary() {
878 assert_eq!(Expression::parse("xq").unwrap().tree_depth(), 2); assert_eq!(Expression::parse("xs").unwrap().tree_depth(), 2); assert_eq!(Expression::parse("xn").unwrap().tree_depth(), 2); }
883
884 #[test]
885 fn test_tree_depth_binary() {
886 assert_eq!(Expression::parse("12+").unwrap().tree_depth(), 2); assert_eq!(Expression::parse("x2*").unwrap().tree_depth(), 2); assert_eq!(Expression::parse("x1+2*").unwrap().tree_depth(), 3); }
891
892 #[test]
893 fn test_tree_depth_nested() {
894 assert_eq!(Expression::parse("xqq").unwrap().tree_depth(), 3); assert_eq!(Expression::parse("12+34+*").unwrap().tree_depth(), 3); }
898
899 #[test]
900 fn test_tree_depth_empty() {
901 assert_eq!(Expression::new().tree_depth(), 0);
903 }
904
905 #[test]
906 fn test_tree_depth_malformed() {
907 assert_eq!(
909 Expression::from_symbols(&[Symbol::X, Symbol::One]).tree_depth(),
910 0
911 );
912 }
913
914 #[test]
915 fn test_operator_count_atom() {
916 assert_eq!(Expression::parse("x").unwrap().operator_count(), 0);
918 assert_eq!(Expression::parse("1").unwrap().operator_count(), 0);
919 assert_eq!(Expression::parse("p").unwrap().operator_count(), 0);
920 }
921
922 #[test]
923 fn test_operator_count_unary() {
924 assert_eq!(Expression::parse("xq").unwrap().operator_count(), 1);
926 assert_eq!(Expression::parse("xs").unwrap().operator_count(), 1);
927 assert_eq!(Expression::parse("xn").unwrap().operator_count(), 1);
928 }
929
930 #[test]
931 fn test_operator_count_binary() {
932 assert_eq!(Expression::parse("12+").unwrap().operator_count(), 1);
934 assert_eq!(Expression::parse("x2*").unwrap().operator_count(), 1);
935 }
936
937 #[test]
938 fn test_operator_count_complex() {
939 assert_eq!(Expression::parse("x1+2*").unwrap().operator_count(), 2); assert_eq!(Expression::parse("xq1+").unwrap().operator_count(), 2); assert_eq!(Expression::parse("12+34+*").unwrap().operator_count(), 3); }
944
945 #[test]
946 fn test_operator_count_empty() {
947 assert_eq!(Expression::new().operator_count(), 0);
948 }
949
950 #[test]
951 fn test_push_pop_complexity_saturating() {
952 let mut expr = Expression::new();
953
954 for _ in 0..1000 {
956 expr.push(Symbol::X);
957 }
958 assert!(expr.complexity() < u32::MAX);
960
961 for _ in 0..1000 {
963 expr.pop();
964 }
965 assert_eq!(expr.complexity(), 0);
967 }
968
969 #[test]
973 #[should_panic(expected = "stack underflow in to_infix")]
974 fn test_to_infix_panics_on_malformed_expression() {
975 let expr = Expression::from_symbols(&[Symbol::Add]);
978 let _ = expr.to_infix();
979 }
980}