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
26#[derive(Clone, PartialEq, Eq, Hash)]
28pub struct Expression {
29 symbols: SmallVec<[Symbol; MAX_EXPR_LEN]>,
31 complexity: u32,
33 contains_x: bool,
35}
36
37impl Expression {
38 pub fn new() -> Self {
40 Self {
41 symbols: SmallVec::new(),
42 complexity: 0,
43 contains_x: false,
44 }
45 }
46
47 #[cfg(test)]
49 pub fn from_symbols(symbols: &[Symbol]) -> Self {
50 let complexity: u32 = symbols
52 .iter()
53 .map(|s| s.weight())
54 .fold(0u32, |acc, w| acc.saturating_add(w));
55 let contains_x = symbols.contains(&Symbol::X);
56 Self {
57 symbols: SmallVec::from_slice(symbols),
58 complexity,
59 contains_x,
60 }
61 }
62
63 pub fn parse(s: &str) -> Option<Self> {
69 let mut symbols = SmallVec::new();
70 for b in s.bytes() {
71 symbols.push(Symbol::from_byte(b)?);
72 }
73 if !Self::is_valid_postfix(&symbols) {
74 return None;
75 }
76 let complexity: u32 = symbols
78 .iter()
79 .map(|s: &Symbol| s.weight())
80 .fold(0u32, |acc, w| acc.saturating_add(w));
81 let contains_x = symbols.contains(&Symbol::X);
82 Some(Self {
83 symbols,
84 complexity,
85 contains_x,
86 })
87 }
88
89 #[inline]
91 pub fn symbols(&self) -> &[Symbol] {
92 &self.symbols
93 }
94
95 #[inline]
97 pub fn len(&self) -> usize {
98 self.symbols.len()
99 }
100
101 #[inline]
103 pub fn is_empty(&self) -> bool {
104 self.symbols.is_empty()
105 }
106
107 #[inline]
109 pub fn complexity(&self) -> u32 {
110 self.complexity
111 }
112
113 #[inline]
115 pub fn contains_x(&self) -> bool {
116 self.contains_x
117 }
118
119 #[inline]
121 pub fn count_symbol(&self, sym: Symbol) -> u32 {
122 self.symbols.iter().filter(|&&s| s == sym).count() as u32
123 }
124
125 #[allow(dead_code)]
130 pub fn is_valid(&self) -> bool {
131 Self::is_valid_postfix(&self.symbols)
132 }
133
134 fn is_valid_postfix(symbols: &[Symbol]) -> bool {
135 let mut depth: i32 = 0;
136 for sym in symbols {
137 match sym.seft() {
138 Seft::A => depth += 1,
139 Seft::B => { }
140 Seft::C => depth -= 1, }
142 if depth < 1 {
143 return false; }
145 }
146 depth == 1
147 }
148
149 pub fn push(&mut self, sym: Symbol) {
151 self.complexity = self.complexity.saturating_add(sym.weight());
153 if sym == Symbol::X {
154 self.contains_x = true;
155 }
156 self.symbols.push(sym);
157 }
158
159 pub fn pop(&mut self) -> Option<Symbol> {
161 let sym = self.symbols.pop()?;
162 self.complexity = self.complexity.saturating_sub(sym.weight());
164 if sym == Symbol::X {
166 self.contains_x = self.symbols.contains(&Symbol::X);
167 }
168 Some(sym)
169 }
170
171 pub fn push_with_table(&mut self, sym: Symbol, table: &crate::symbol_table::SymbolTable) {
176 self.complexity = self.complexity.saturating_add(table.weight(sym));
178 if sym == Symbol::X {
179 self.contains_x = true;
180 }
181 self.symbols.push(sym);
182 }
183
184 pub fn pop_with_table(&mut self, table: &crate::symbol_table::SymbolTable) -> Option<Symbol> {
189 let sym = self.symbols.pop()?;
190 self.complexity = self.complexity.saturating_sub(table.weight(sym));
192 if sym == Symbol::X {
194 self.contains_x = self.symbols.contains(&Symbol::X);
195 }
196 Some(sym)
197 }
198
199 pub fn to_postfix(&self) -> String {
201 self.symbols.iter().map(|s| *s as u8 as char).collect()
202 }
203
204 pub fn try_to_infix(&self) -> Result<String, crate::eval::EvalError> {
222 const PREC_ATOM: u8 = 100;
223 const PREC_POWER: u8 = 9;
224 const PREC_UNARY: u8 = 8;
225 const PREC_MUL: u8 = 6;
226 const PREC_ADD: u8 = 4;
227
228 fn needs_paren(
229 parent_prec: u8,
230 child_prec: u8,
231 is_right_assoc: bool,
232 is_right_operand: bool,
233 ) -> bool {
234 if child_prec < parent_prec {
235 return true;
236 }
237 if is_right_assoc && is_right_operand && child_prec == parent_prec {
238 return true;
239 }
240 false
241 }
242
243 fn maybe_paren_prec(
244 s: &str,
245 prec: u8,
246 parent_prec: u8,
247 is_right_assoc: bool,
248 is_right: bool,
249 ) -> String {
250 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
251 format!("({})", s)
252 } else {
253 s.to_string()
254 }
255 }
256
257 let mut stack: Vec<(String, u8)> = Vec::new();
258
259 for &sym in &self.symbols {
260 match sym.seft() {
261 Seft::A => {
262 stack.push((sym.display_name(), PREC_ATOM));
263 }
264 Seft::B => {
265 let (arg, arg_prec) =
266 stack.pop().ok_or(crate::eval::EvalError::StackUnderflow)?;
267 let result = match sym {
268 Symbol::Neg => {
269 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_UNARY, false, false);
270 format!("-{}", arg_s)
271 }
272 Symbol::Recip => {
273 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_MUL, false, false);
274 format!("1/{}", arg_s)
275 }
276 Symbol::Sqrt => format!("sqrt({})", arg),
277 Symbol::Square => {
278 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, false, false);
279 format!("{}^2", arg_s)
280 }
281 Symbol::Ln => format!("ln({})", arg),
282 Symbol::Exp => {
283 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, true, true);
284 format!("e^{}", arg_s)
285 }
286 Symbol::SinPi => format!("sinpi({})", arg),
287 Symbol::CosPi => format!("cospi({})", arg),
288 Symbol::TanPi => format!("tanpi({})", arg),
289 Symbol::LambertW => format!("W({})", arg),
290 Symbol::UserFunction0
291 | Symbol::UserFunction1
292 | Symbol::UserFunction2
293 | Symbol::UserFunction3
294 | Symbol::UserFunction4
295 | Symbol::UserFunction5
296 | Symbol::UserFunction6
297 | Symbol::UserFunction7
298 | Symbol::UserFunction8
299 | Symbol::UserFunction9
300 | Symbol::UserFunction10
301 | Symbol::UserFunction11
302 | Symbol::UserFunction12
303 | Symbol::UserFunction13
304 | Symbol::UserFunction14
305 | Symbol::UserFunction15 => format!("{}({})", sym.display_name(), arg),
306 _ => "?".to_string(),
307 };
308 stack.push((result, PREC_ATOM));
309 }
310 Seft::C => {
311 let (b, b_prec) = stack.pop().ok_or(crate::eval::EvalError::StackUnderflow)?;
312 let (a, a_prec) = stack.pop().ok_or(crate::eval::EvalError::StackUnderflow)?;
313 let (result, prec) = match sym {
314 Symbol::Add => {
315 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
316 (format!("{}+{}", a, b_s), PREC_ADD)
317 }
318 Symbol::Sub => {
319 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
320 (format!("{}-{}", a, b_s), PREC_ADD)
321 }
322 Symbol::Mul => {
323 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
324 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL, false, true);
325 if a_s.chars().last().is_some_and(|c| c.is_ascii_digit())
326 && b_s.chars().next().is_some_and(|c| c.is_alphabetic())
327 {
328 (format!("{} {}", a_s, b_s), PREC_MUL)
329 } else {
330 (format!("{}*{}", a_s, b_s), PREC_MUL)
331 }
332 }
333 Symbol::Div => {
334 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
335 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL + 1, false, true);
336 (format!("{}/{}", a_s, b_s), PREC_MUL)
337 }
338 Symbol::Pow => {
339 let a_s = maybe_paren_prec(&a, a_prec, PREC_POWER, true, false);
340 let b_s = maybe_paren_prec(&b, b_prec, PREC_POWER, true, true);
341 (format!("{}^{}", a_s, b_s), PREC_POWER)
342 }
343 Symbol::Root => (format!("{}\"/{}", a, b), PREC_POWER),
344 Symbol::Log => (format!("log_{}({})", a, b), PREC_ATOM),
345 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
346 _ => unreachable!(),
347 };
348 stack.push((result, prec));
349 }
350 }
351 }
352
353 Ok(stack.pop().map(|(s, _)| s).unwrap_or_else(|| "?".into()))
354 }
355
356 pub fn to_infix(&self) -> String {
357 self.try_to_infix()
358 .expect("stack underflow in to_infix: expression is not valid postfix")
359 }
360
361 pub fn to_infix_or_postfix(&self) -> String {
366 self.try_to_infix().unwrap_or_else(|_| self.to_postfix())
367 }
368
369 pub fn to_infix_with_table(&self, table: &crate::symbol_table::SymbolTable) -> String {
374 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(
383 parent_prec: u8,
384 child_prec: u8,
385 is_right_assoc: bool,
386 is_right_operand: bool,
387 ) -> bool {
388 if child_prec < parent_prec {
389 return true;
390 }
391 if is_right_assoc && is_right_operand && child_prec == parent_prec {
392 return true;
393 }
394 false
395 }
396
397 fn maybe_paren_prec(
399 s: &str,
400 prec: u8,
401 parent_prec: u8,
402 is_right_assoc: bool,
403 is_right: bool,
404 ) -> String {
405 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
406 format!("({})", s)
407 } else {
408 s.to_string()
409 }
410 }
411
412 let mut stack: Vec<(String, u8)> = Vec::new();
413
414 for &sym in &self.symbols {
415 match sym.seft() {
416 Seft::A => {
417 stack.push((table.name(sym).to_string(), PREC_ATOM));
418 }
419 Seft::B => {
420 let (arg, arg_prec) = stack
421 .pop()
422 .expect("stack underflow in to_infix: expression is not valid postfix");
423 let result = match sym {
424 Symbol::Neg => {
425 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_UNARY, false, false);
426 format!("-{}", arg_s)
427 }
428 Symbol::Recip => {
429 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_MUL, false, false);
430 format!("1/{}", arg_s)
431 }
432 Symbol::Sqrt => format!("sqrt({})", arg),
433 Symbol::Square => {
434 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, false, false);
435 format!("{}^2", arg_s)
436 }
437 Symbol::Ln => format!("ln({})", arg),
438 Symbol::Exp => {
439 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, true, true);
440 format!("e^{}", arg_s)
441 }
442 Symbol::SinPi => format!("sinpi({})", arg),
443 Symbol::CosPi => format!("cospi({})", arg),
444 Symbol::TanPi => format!("tanpi({})", arg),
445 Symbol::LambertW => format!("W({})", arg),
446 Symbol::UserFunction0
447 | Symbol::UserFunction1
448 | Symbol::UserFunction2
449 | Symbol::UserFunction3
450 | Symbol::UserFunction4
451 | Symbol::UserFunction5
452 | Symbol::UserFunction6
453 | Symbol::UserFunction7
454 | Symbol::UserFunction8
455 | Symbol::UserFunction9
456 | Symbol::UserFunction10
457 | Symbol::UserFunction11
458 | Symbol::UserFunction12
459 | Symbol::UserFunction13
460 | Symbol::UserFunction14
461 | Symbol::UserFunction15 => format!("{}({})", table.name(sym), arg),
462 _ => "?".to_string(),
463 };
464 stack.push((result, PREC_ATOM));
465 }
466 Seft::C => {
467 let (b, b_prec) = stack
468 .pop()
469 .expect("stack underflow in to_infix: expression is not valid postfix");
470 let (a, a_prec) = stack
471 .pop()
472 .expect("stack underflow in to_infix: expression is not valid postfix");
473 let (result, prec) = match sym {
474 Symbol::Add => {
475 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
476 (format!("{}+{}", a, b_s), PREC_ADD)
477 }
478 Symbol::Sub => {
479 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
480 (format!("{}-{}", a, b_s), PREC_ADD)
481 }
482 Symbol::Mul => {
483 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
484 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL, false, true);
485 if a_s.chars().last().is_some_and(|c| c.is_ascii_digit())
486 && b_s.chars().next().is_some_and(|c| c.is_alphabetic())
487 {
488 (format!("{} {}", a_s, b_s), PREC_MUL)
489 } else {
490 (format!("{}*{}", a_s, b_s), PREC_MUL)
491 }
492 }
493 Symbol::Div => {
494 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
495 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL + 1, false, true);
496 (format!("{}/{}", a_s, b_s), PREC_MUL)
497 }
498 Symbol::Pow => {
499 let a_s = maybe_paren_prec(&a, a_prec, PREC_POWER, true, false);
500 let b_s = maybe_paren_prec(&b, b_prec, PREC_POWER, true, true);
501 (format!("{}^{}", a_s, b_s), PREC_POWER)
502 }
503 Symbol::Root => (format!("{}\"/{}", a, b), PREC_POWER),
504 Symbol::Log => (format!("log_{}({})", a, b), PREC_ATOM),
505 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
506 _ => unreachable!(),
507 };
508 stack.push((result, prec));
509 }
510 }
511 }
512
513 stack.pop().map(|(s, _)| s).unwrap_or_else(|| "?".into())
514 }
515
516 pub fn to_infix_with_format(&self, format: OutputFormat) -> String {
518 match format {
519 OutputFormat::Default => self.to_infix(),
520 OutputFormat::Pretty => {
521 let mut result = self.to_infix();
522 result = result.replace("pi", "π");
524 result = result.replace("sqrt(", "√(");
525 result = result.replace("^2", "²");
526 result
527 }
528 OutputFormat::Mathematica => self.to_infix_mathematica(),
529 OutputFormat::SymPy => self.to_infix_sympy(),
530 }
531 }
532
533 pub fn operator_count(&self) -> usize {
535 self.symbols
536 .iter()
537 .filter(|sym| sym.seft() != Seft::A)
538 .count()
539 }
540
541 pub fn tree_depth(&self) -> usize {
543 let mut stack: Vec<usize> = Vec::with_capacity(self.len());
544 for &sym in &self.symbols {
545 match sym.seft() {
546 Seft::A => stack.push(1),
547 Seft::B => {
548 let Some(arg_depth) = stack.pop() else {
549 return 0;
550 };
551 stack.push(arg_depth.saturating_add(1));
552 }
553 Seft::C => {
554 let Some(rhs_depth) = stack.pop() else {
555 return 0;
556 };
557 let Some(lhs_depth) = stack.pop() else {
558 return 0;
559 };
560 stack.push(lhs_depth.max(rhs_depth).saturating_add(1));
561 }
562 }
563 }
564 if stack.len() == 1 {
565 stack[0]
566 } else {
567 0
568 }
569 }
570
571 pub fn to_infix_mathematica(&self) -> String {
572 const PREC_ATOM: u8 = 100;
573 const PREC_POWER: u8 = 9;
574 const PREC_UNARY: u8 = 8;
575 const PREC_MUL: u8 = 6;
576 const PREC_ADD: u8 = 4;
577
578 fn needs_paren(
579 parent_prec: u8,
580 child_prec: u8,
581 is_right_assoc: bool,
582 is_right_operand: bool,
583 ) -> bool {
584 if child_prec < parent_prec {
585 return true;
586 }
587 if is_right_assoc && is_right_operand && child_prec == parent_prec {
588 return true;
589 }
590 false
591 }
592
593 fn maybe_paren(
594 s: &str,
595 prec: u8,
596 parent_prec: u8,
597 is_right_assoc: bool,
598 is_right: bool,
599 ) -> String {
600 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
601 format!("({})", s)
602 } else {
603 s.to_string()
604 }
605 }
606
607 let mut stack: Vec<(String, u8)> = Vec::new();
608
609 for &sym in &self.symbols {
610 match sym.seft() {
611 Seft::A => {
612 let s = match sym {
613 Symbol::Pi => "Pi",
614 Symbol::E => "E",
615 Symbol::Phi => "GoldenRatio",
616 Symbol::Gamma => "EulerGamma",
617 Symbol::Apery => "Zeta[3]",
618 Symbol::Catalan => "Catalan",
619 _ => "",
620 };
621 let name = if s.is_empty() {
622 sym.display_name()
623 } else {
624 s.to_string()
625 };
626 stack.push((name, PREC_ATOM));
627 }
628 Seft::B => {
629 let (arg, arg_prec) = stack
630 .pop()
631 .expect("stack underflow in to_infix: expression is not valid postfix");
632 let result = match sym {
633 Symbol::Neg => {
634 let s = maybe_paren(&arg, arg_prec, PREC_UNARY, false, false);
635 format!("-{}", s)
636 }
637 Symbol::Recip => {
638 let s = maybe_paren(&arg, arg_prec, PREC_MUL, false, false);
639 format!("1/{}", s)
640 }
641 Symbol::Sqrt => format!("Sqrt[{}]", arg),
642 Symbol::Square => {
643 let s = maybe_paren(&arg, arg_prec, PREC_POWER, false, false);
644 format!("{}^2", s)
645 }
646 Symbol::Ln => format!("Log[{}]", arg),
647 Symbol::Exp => format!("Exp[{}]", arg),
648 Symbol::SinPi => format!("Sin[Pi*{}]", arg),
649 Symbol::CosPi => format!("Cos[Pi*{}]", arg),
650 Symbol::TanPi => format!("Tan[Pi*{}]", arg),
651 Symbol::LambertW => format!("ProductLog[{}]", arg),
652 Symbol::UserFunction0
653 | Symbol::UserFunction1
654 | Symbol::UserFunction2
655 | Symbol::UserFunction3
656 | Symbol::UserFunction4
657 | Symbol::UserFunction5
658 | Symbol::UserFunction6
659 | Symbol::UserFunction7
660 | Symbol::UserFunction8
661 | Symbol::UserFunction9
662 | Symbol::UserFunction10
663 | Symbol::UserFunction11
664 | Symbol::UserFunction12
665 | Symbol::UserFunction13
666 | Symbol::UserFunction14
667 | Symbol::UserFunction15 => format!("{}[{}]", sym.display_name(), arg),
668 _ => "?".to_string(),
669 };
670 stack.push((result, PREC_ATOM));
671 }
672 Seft::C => {
673 let (b, b_prec) = stack
674 .pop()
675 .expect("stack underflow in to_infix: expression is not valid postfix");
676 let (a, a_prec) = stack
677 .pop()
678 .expect("stack underflow in to_infix: expression is not valid postfix");
679 let (result, prec) = match sym {
680 Symbol::Add => {
681 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
682 (format!("{}+{}", a, b_s), PREC_ADD)
683 }
684 Symbol::Sub => {
685 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
686 (format!("{}-{}", a, b_s), PREC_ADD)
687 }
688 Symbol::Mul => {
689 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
690 let b_s = maybe_paren(&b, b_prec, PREC_MUL, false, true);
691 (format!("{}*{}", a_s, b_s), PREC_MUL)
692 }
693 Symbol::Div => {
694 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
695 let b_s = maybe_paren(&b, b_prec, PREC_MUL + 1, false, true);
696 (format!("{}/{}", a_s, b_s), PREC_MUL)
697 }
698 Symbol::Pow => {
699 let a_s = maybe_paren(&a, a_prec, PREC_POWER, true, false);
700 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, true);
701 (format!("{}^{}", a_s, b_s), PREC_POWER)
702 }
703 Symbol::Root => {
704 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, false);
705 (format!("{}^(1/{})", b_s, a), PREC_POWER)
706 }
707 Symbol::Log => (format!("Log[{}, {}]", a, b), PREC_ATOM),
708 Symbol::Atan2 => (format!("ArcTan[{}, {}]", b, a), PREC_ATOM),
709 _ => unreachable!(),
710 };
711 stack.push((result, prec));
712 }
713 }
714 }
715
716 stack
717 .pop()
718 .map(|(s, _)| s)
719 .unwrap_or_else(|| "?".to_string())
720 }
721
722 pub fn to_infix_sympy(&self) -> String {
723 const PREC_ATOM: u8 = 100;
724 const PREC_POWER: u8 = 9;
725 const PREC_UNARY: u8 = 8;
726 const PREC_MUL: u8 = 6;
727 const PREC_ADD: u8 = 4;
728
729 fn needs_paren(
730 parent_prec: u8,
731 child_prec: u8,
732 is_right_assoc: bool,
733 is_right_operand: bool,
734 ) -> bool {
735 if child_prec < parent_prec {
736 return true;
737 }
738 if is_right_assoc && is_right_operand && child_prec == parent_prec {
739 return true;
740 }
741 false
742 }
743
744 fn maybe_paren(
745 s: &str,
746 prec: u8,
747 parent_prec: u8,
748 is_right_assoc: bool,
749 is_right: bool,
750 ) -> String {
751 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
752 format!("({})", s)
753 } else {
754 s.to_string()
755 }
756 }
757
758 let mut stack: Vec<(String, u8)> = Vec::new();
759
760 for &sym in &self.symbols {
761 match sym.seft() {
762 Seft::A => {
763 let s = match sym {
764 Symbol::Pi => "pi",
765 Symbol::E => "E",
766 Symbol::Phi => "GoldenRatio",
767 Symbol::Gamma => "EulerGamma",
768 Symbol::Apery => "zeta(3)",
769 Symbol::Catalan => "Catalan",
770 _ => "",
771 };
772 let name = if s.is_empty() {
773 sym.display_name()
774 } else {
775 s.to_string()
776 };
777 stack.push((name, PREC_ATOM));
778 }
779 Seft::B => {
780 let (arg, arg_prec) = stack
781 .pop()
782 .expect("stack underflow in to_infix: expression is not valid postfix");
783 let result = match sym {
784 Symbol::Neg => {
785 let s = maybe_paren(&arg, arg_prec, PREC_UNARY, false, false);
786 format!("-{}", s)
787 }
788 Symbol::Recip => {
789 let s = maybe_paren(&arg, arg_prec, PREC_MUL, false, false);
790 format!("1/{}", s)
791 }
792 Symbol::Sqrt => format!("sqrt({})", arg),
793 Symbol::Square => {
794 let s = maybe_paren(&arg, arg_prec, PREC_POWER, false, false);
795 format!("{}**2", s)
796 }
797 Symbol::Ln => format!("log({})", arg),
798 Symbol::Exp => format!("exp({})", arg),
799 Symbol::SinPi => format!("sin(pi*{})", arg),
800 Symbol::CosPi => format!("cos(pi*{})", arg),
801 Symbol::TanPi => format!("tan(pi*{})", arg),
802 Symbol::LambertW => format!("lambertw({})", arg),
803 Symbol::UserFunction0
804 | Symbol::UserFunction1
805 | Symbol::UserFunction2
806 | Symbol::UserFunction3
807 | Symbol::UserFunction4
808 | Symbol::UserFunction5
809 | Symbol::UserFunction6
810 | Symbol::UserFunction7
811 | Symbol::UserFunction8
812 | Symbol::UserFunction9
813 | Symbol::UserFunction10
814 | Symbol::UserFunction11
815 | Symbol::UserFunction12
816 | Symbol::UserFunction13
817 | Symbol::UserFunction14
818 | Symbol::UserFunction15 => format!("{}({})", sym.display_name(), arg),
819 _ => "?".to_string(),
820 };
821 stack.push((result, PREC_ATOM));
822 }
823 Seft::C => {
824 let (b, b_prec) = stack
825 .pop()
826 .expect("stack underflow in to_infix: expression is not valid postfix");
827 let (a, a_prec) = stack
828 .pop()
829 .expect("stack underflow in to_infix: expression is not valid postfix");
830 let (result, prec) = match sym {
831 Symbol::Add => {
832 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
833 (format!("{}+{}", a, b_s), PREC_ADD)
834 }
835 Symbol::Sub => {
836 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
837 (format!("{}-{}", a, b_s), PREC_ADD)
838 }
839 Symbol::Mul => {
840 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
841 let b_s = maybe_paren(&b, b_prec, PREC_MUL, false, true);
842 (format!("{}*{}", a_s, b_s), PREC_MUL)
843 }
844 Symbol::Div => {
845 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
846 let b_s = maybe_paren(&b, b_prec, PREC_MUL + 1, false, true);
847 (format!("{}/{}", a_s, b_s), PREC_MUL)
848 }
849 Symbol::Pow => {
850 let a_s = maybe_paren(&a, a_prec, PREC_POWER, true, false);
851 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, true);
852 (format!("{}**{}", a_s, b_s), PREC_POWER)
853 }
854 Symbol::Root => {
855 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, false);
856 (format!("{}**(1/{})", b_s, a), PREC_POWER)
857 }
858 Symbol::Log => (format!("log({}, {})", b, a), PREC_ATOM),
859 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
860 _ => unreachable!(),
861 };
862 stack.push((result, prec));
863 }
864 }
865 }
866
867 stack
868 .pop()
869 .map(|(s, _)| s)
870 .unwrap_or_else(|| "?".to_string())
871 }
872}
873
874impl Default for Expression {
875 fn default() -> Self {
876 Self::new()
877 }
878}
879
880impl fmt::Display for Expression {
881 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
882 write!(f, "{}", self.to_infix())
883 }
884}
885
886impl fmt::Debug for Expression {
887 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
888 write!(f, "Expr[{}] = {}", self.to_postfix(), self.to_infix())
889 }
890}
891
892#[derive(Clone, Debug)]
894pub struct EvaluatedExpr {
895 pub expr: Expression,
897 pub value: f64,
899 pub derivative: f64,
901 #[allow(dead_code)]
906 pub num_type: NumType,
907}
908
909impl EvaluatedExpr {
910 pub fn new(expr: Expression, value: f64, derivative: f64, num_type: NumType) -> Self {
911 Self {
912 expr,
913 value,
914 derivative,
915 num_type,
916 }
917 }
918}
919
920#[cfg(test)]
921mod tests {
922 use super::*;
923
924 #[test]
925 fn test_parse_expression() {
926 let expr = Expression::parse("32+").unwrap();
927 assert_eq!(expr.len(), 3);
928 assert_eq!(expr.to_postfix(), "32+");
929 assert!(!expr.contains_x());
930 }
931
932 #[test]
933 fn test_expression_validity() {
934 assert!(Expression::parse("32+").unwrap().is_valid());
936
937 assert!(Expression::parse("xs").unwrap().is_valid());
939
940 assert!(Expression::parse("3+").is_none());
942
943 assert!(Expression::parse("32").is_none());
945 }
946
947 #[test]
948 fn test_infix_conversion() {
949 assert_eq!(Expression::parse("32+").unwrap().to_infix(), "3+2");
950 assert_eq!(Expression::parse("32*").unwrap().to_infix(), "3*2");
951 assert_eq!(Expression::parse("xs").unwrap().to_infix(), "x^2");
952 assert_eq!(Expression::parse("xq").unwrap().to_infix(), "sqrt(x)");
953 assert_eq!(Expression::parse("32+5*").unwrap().to_infix(), "(3+2)*5");
954 }
955
956 #[test]
957 fn test_complexity() {
958 let expr = Expression::parse("xs").unwrap(); assert_eq!(expr.complexity(), 15 + 9);
961 }
962
963 #[test]
964 fn test_tree_depth_atom() {
965 assert_eq!(Expression::parse("x").unwrap().tree_depth(), 1);
967 assert_eq!(Expression::parse("1").unwrap().tree_depth(), 1);
968 assert_eq!(Expression::parse("p").unwrap().tree_depth(), 1); }
970
971 #[test]
972 fn test_tree_depth_unary() {
973 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); }
978
979 #[test]
980 fn test_tree_depth_binary() {
981 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); }
986
987 #[test]
988 fn test_tree_depth_nested() {
989 assert_eq!(Expression::parse("xqq").unwrap().tree_depth(), 3); assert_eq!(Expression::parse("12+34+*").unwrap().tree_depth(), 3); }
993
994 #[test]
995 fn test_tree_depth_empty() {
996 assert_eq!(Expression::new().tree_depth(), 0);
998 }
999
1000 #[test]
1001 fn test_tree_depth_malformed() {
1002 assert_eq!(
1004 Expression::from_symbols(&[Symbol::X, Symbol::One]).tree_depth(),
1005 0
1006 );
1007 }
1008
1009 #[test]
1010 fn test_operator_count_atom() {
1011 assert_eq!(Expression::parse("x").unwrap().operator_count(), 0);
1013 assert_eq!(Expression::parse("1").unwrap().operator_count(), 0);
1014 assert_eq!(Expression::parse("p").unwrap().operator_count(), 0);
1015 }
1016
1017 #[test]
1018 fn test_operator_count_unary() {
1019 assert_eq!(Expression::parse("xq").unwrap().operator_count(), 1);
1021 assert_eq!(Expression::parse("xs").unwrap().operator_count(), 1);
1022 assert_eq!(Expression::parse("xn").unwrap().operator_count(), 1);
1023 }
1024
1025 #[test]
1026 fn test_operator_count_binary() {
1027 assert_eq!(Expression::parse("12+").unwrap().operator_count(), 1);
1029 assert_eq!(Expression::parse("x2*").unwrap().operator_count(), 1);
1030 }
1031
1032 #[test]
1033 fn test_operator_count_complex() {
1034 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); }
1039
1040 #[test]
1041 fn test_operator_count_empty() {
1042 assert_eq!(Expression::new().operator_count(), 0);
1043 }
1044
1045 #[test]
1046 fn test_push_pop_complexity_saturating() {
1047 let mut expr = Expression::new();
1048
1049 for _ in 0..1000 {
1051 expr.push(Symbol::X);
1052 }
1053 assert!(expr.complexity() < u32::MAX);
1055
1056 for _ in 0..1000 {
1058 expr.pop();
1059 }
1060 assert_eq!(expr.complexity(), 0);
1062 }
1063
1064 #[test]
1068 #[should_panic(expected = "stack underflow in to_infix")]
1069 fn test_to_infix_panics_on_malformed_expression() {
1070 let expr = Expression::from_symbols(&[Symbol::Add]);
1073 let _ = expr.to_infix();
1074 }
1075
1076 #[test]
1077 fn test_try_to_infix_returns_err_on_malformed_expression() {
1078 let expr = Expression::from_symbols(&[Symbol::Add]);
1081 let result = expr.try_to_infix();
1082 assert!(
1083 result.is_err(),
1084 "try_to_infix on malformed expression should return Err, got Ok({:?})",
1085 result.ok()
1086 );
1087 }
1088
1089 #[test]
1090 fn test_to_infix_or_postfix_falls_back_on_malformed_expression() {
1091 let expr = Expression::from_symbols(&[Symbol::Add]);
1092 assert_eq!(expr.to_infix_or_postfix(), expr.to_postfix());
1093 }
1094
1095 #[test]
1096 fn test_try_to_infix_succeeds_on_valid_expression() {
1097 let expr = Expression::parse("32+").unwrap();
1098 let result = expr.try_to_infix();
1099 assert_eq!(result.unwrap(), "3+2");
1100 }
1101}