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_with_table(&self, table: &crate::symbol_table::SymbolTable) -> String {
366 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(
375 parent_prec: u8,
376 child_prec: u8,
377 is_right_assoc: bool,
378 is_right_operand: bool,
379 ) -> bool {
380 if child_prec < parent_prec {
381 return true;
382 }
383 if is_right_assoc && is_right_operand && child_prec == parent_prec {
384 return true;
385 }
386 false
387 }
388
389 fn maybe_paren_prec(
391 s: &str,
392 prec: u8,
393 parent_prec: u8,
394 is_right_assoc: bool,
395 is_right: bool,
396 ) -> String {
397 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
398 format!("({})", s)
399 } else {
400 s.to_string()
401 }
402 }
403
404 let mut stack: Vec<(String, u8)> = Vec::new();
405
406 for &sym in &self.symbols {
407 match sym.seft() {
408 Seft::A => {
409 stack.push((table.name(sym).to_string(), PREC_ATOM));
410 }
411 Seft::B => {
412 let (arg, arg_prec) = stack
413 .pop()
414 .expect("stack underflow in to_infix: expression is not valid postfix");
415 let result = match sym {
416 Symbol::Neg => {
417 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_UNARY, false, false);
418 format!("-{}", arg_s)
419 }
420 Symbol::Recip => {
421 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_MUL, false, false);
422 format!("1/{}", arg_s)
423 }
424 Symbol::Sqrt => format!("sqrt({})", arg),
425 Symbol::Square => {
426 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, false, false);
427 format!("{}^2", arg_s)
428 }
429 Symbol::Ln => format!("ln({})", arg),
430 Symbol::Exp => {
431 let arg_s = maybe_paren_prec(&arg, arg_prec, PREC_POWER, true, true);
432 format!("e^{}", arg_s)
433 }
434 Symbol::SinPi => format!("sinpi({})", arg),
435 Symbol::CosPi => format!("cospi({})", arg),
436 Symbol::TanPi => format!("tanpi({})", arg),
437 Symbol::LambertW => format!("W({})", arg),
438 Symbol::UserFunction0
439 | Symbol::UserFunction1
440 | Symbol::UserFunction2
441 | Symbol::UserFunction3
442 | Symbol::UserFunction4
443 | Symbol::UserFunction5
444 | Symbol::UserFunction6
445 | Symbol::UserFunction7
446 | Symbol::UserFunction8
447 | Symbol::UserFunction9
448 | Symbol::UserFunction10
449 | Symbol::UserFunction11
450 | Symbol::UserFunction12
451 | Symbol::UserFunction13
452 | Symbol::UserFunction14
453 | Symbol::UserFunction15 => format!("{}({})", table.name(sym), arg),
454 _ => "?".to_string(),
455 };
456 stack.push((result, PREC_ATOM));
457 }
458 Seft::C => {
459 let (b, b_prec) = stack
460 .pop()
461 .expect("stack underflow in to_infix: expression is not valid postfix");
462 let (a, a_prec) = stack
463 .pop()
464 .expect("stack underflow in to_infix: expression is not valid postfix");
465 let (result, prec) = match sym {
466 Symbol::Add => {
467 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
468 (format!("{}+{}", a, b_s), PREC_ADD)
469 }
470 Symbol::Sub => {
471 let b_s = maybe_paren_prec(&b, b_prec, PREC_ADD, false, true);
472 (format!("{}-{}", a, b_s), PREC_ADD)
473 }
474 Symbol::Mul => {
475 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
476 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL, false, true);
477 if a_s.chars().last().is_some_and(|c| c.is_ascii_digit())
478 && b_s.chars().next().is_some_and(|c| c.is_alphabetic())
479 {
480 (format!("{} {}", a_s, b_s), PREC_MUL)
481 } else {
482 (format!("{}*{}", a_s, b_s), PREC_MUL)
483 }
484 }
485 Symbol::Div => {
486 let a_s = maybe_paren_prec(&a, a_prec, PREC_MUL, false, false);
487 let b_s = maybe_paren_prec(&b, b_prec, PREC_MUL + 1, false, true);
488 (format!("{}/{}", a_s, b_s), PREC_MUL)
489 }
490 Symbol::Pow => {
491 let a_s = maybe_paren_prec(&a, a_prec, PREC_POWER, true, false);
492 let b_s = maybe_paren_prec(&b, b_prec, PREC_POWER, true, true);
493 (format!("{}^{}", a_s, b_s), PREC_POWER)
494 }
495 Symbol::Root => (format!("{}\"/{}", a, b), PREC_POWER),
496 Symbol::Log => (format!("log_{}({})", a, b), PREC_ATOM),
497 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
498 _ => unreachable!(),
499 };
500 stack.push((result, prec));
501 }
502 }
503 }
504
505 stack.pop().map(|(s, _)| s).unwrap_or_else(|| "?".into())
506 }
507
508 pub fn to_infix_with_format(&self, format: OutputFormat) -> String {
510 match format {
511 OutputFormat::Default => self.to_infix(),
512 OutputFormat::Pretty => {
513 let mut result = self.to_infix();
514 result = result.replace("pi", "π");
516 result = result.replace("sqrt(", "√(");
517 result = result.replace("^2", "²");
518 result
519 }
520 OutputFormat::Mathematica => self.to_infix_mathematica(),
521 OutputFormat::SymPy => self.to_infix_sympy(),
522 }
523 }
524
525 pub fn operator_count(&self) -> usize {
527 self.symbols
528 .iter()
529 .filter(|sym| sym.seft() != Seft::A)
530 .count()
531 }
532
533 pub fn tree_depth(&self) -> usize {
535 let mut stack: Vec<usize> = Vec::with_capacity(self.len());
536 for &sym in &self.symbols {
537 match sym.seft() {
538 Seft::A => stack.push(1),
539 Seft::B => {
540 let Some(arg_depth) = stack.pop() else {
541 return 0;
542 };
543 stack.push(arg_depth.saturating_add(1));
544 }
545 Seft::C => {
546 let Some(rhs_depth) = stack.pop() else {
547 return 0;
548 };
549 let Some(lhs_depth) = stack.pop() else {
550 return 0;
551 };
552 stack.push(lhs_depth.max(rhs_depth).saturating_add(1));
553 }
554 }
555 }
556 if stack.len() == 1 {
557 stack[0]
558 } else {
559 0
560 }
561 }
562
563 pub fn to_infix_mathematica(&self) -> String {
564 const PREC_ATOM: u8 = 100;
565 const PREC_POWER: u8 = 9;
566 const PREC_UNARY: u8 = 8;
567 const PREC_MUL: u8 = 6;
568 const PREC_ADD: u8 = 4;
569
570 fn needs_paren(
571 parent_prec: u8,
572 child_prec: u8,
573 is_right_assoc: bool,
574 is_right_operand: bool,
575 ) -> bool {
576 if child_prec < parent_prec {
577 return true;
578 }
579 if is_right_assoc && is_right_operand && child_prec == parent_prec {
580 return true;
581 }
582 false
583 }
584
585 fn maybe_paren(
586 s: &str,
587 prec: u8,
588 parent_prec: u8,
589 is_right_assoc: bool,
590 is_right: bool,
591 ) -> String {
592 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
593 format!("({})", s)
594 } else {
595 s.to_string()
596 }
597 }
598
599 let mut stack: Vec<(String, u8)> = Vec::new();
600
601 for &sym in &self.symbols {
602 match sym.seft() {
603 Seft::A => {
604 let s = match sym {
605 Symbol::Pi => "Pi",
606 Symbol::E => "E",
607 Symbol::Phi => "GoldenRatio",
608 Symbol::Gamma => "EulerGamma",
609 Symbol::Apery => "Zeta[3]",
610 Symbol::Catalan => "Catalan",
611 _ => "",
612 };
613 let name = if s.is_empty() {
614 sym.display_name()
615 } else {
616 s.to_string()
617 };
618 stack.push((name, PREC_ATOM));
619 }
620 Seft::B => {
621 let (arg, arg_prec) = stack
622 .pop()
623 .expect("stack underflow in to_infix: expression is not valid postfix");
624 let result = match sym {
625 Symbol::Neg => {
626 let s = maybe_paren(&arg, arg_prec, PREC_UNARY, false, false);
627 format!("-{}", s)
628 }
629 Symbol::Recip => {
630 let s = maybe_paren(&arg, arg_prec, PREC_MUL, false, false);
631 format!("1/{}", s)
632 }
633 Symbol::Sqrt => format!("Sqrt[{}]", arg),
634 Symbol::Square => {
635 let s = maybe_paren(&arg, arg_prec, PREC_POWER, false, false);
636 format!("{}^2", s)
637 }
638 Symbol::Ln => format!("Log[{}]", arg),
639 Symbol::Exp => format!("Exp[{}]", arg),
640 Symbol::SinPi => format!("Sin[Pi*{}]", arg),
641 Symbol::CosPi => format!("Cos[Pi*{}]", arg),
642 Symbol::TanPi => format!("Tan[Pi*{}]", arg),
643 Symbol::LambertW => format!("ProductLog[{}]", arg),
644 Symbol::UserFunction0
645 | Symbol::UserFunction1
646 | Symbol::UserFunction2
647 | Symbol::UserFunction3
648 | Symbol::UserFunction4
649 | Symbol::UserFunction5
650 | Symbol::UserFunction6
651 | Symbol::UserFunction7
652 | Symbol::UserFunction8
653 | Symbol::UserFunction9
654 | Symbol::UserFunction10
655 | Symbol::UserFunction11
656 | Symbol::UserFunction12
657 | Symbol::UserFunction13
658 | Symbol::UserFunction14
659 | Symbol::UserFunction15 => format!("{}[{}]", sym.display_name(), arg),
660 _ => "?".to_string(),
661 };
662 stack.push((result, PREC_ATOM));
663 }
664 Seft::C => {
665 let (b, b_prec) = stack
666 .pop()
667 .expect("stack underflow in to_infix: expression is not valid postfix");
668 let (a, a_prec) = stack
669 .pop()
670 .expect("stack underflow in to_infix: expression is not valid postfix");
671 let (result, prec) = match sym {
672 Symbol::Add => {
673 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
674 (format!("{}+{}", a, b_s), PREC_ADD)
675 }
676 Symbol::Sub => {
677 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
678 (format!("{}-{}", a, b_s), PREC_ADD)
679 }
680 Symbol::Mul => {
681 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
682 let b_s = maybe_paren(&b, b_prec, PREC_MUL, false, true);
683 (format!("{}*{}", a_s, b_s), PREC_MUL)
684 }
685 Symbol::Div => {
686 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
687 let b_s = maybe_paren(&b, b_prec, PREC_MUL + 1, false, true);
688 (format!("{}/{}", a_s, b_s), PREC_MUL)
689 }
690 Symbol::Pow => {
691 let a_s = maybe_paren(&a, a_prec, PREC_POWER, true, false);
692 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, true);
693 (format!("{}^{}", a_s, b_s), PREC_POWER)
694 }
695 Symbol::Root => {
696 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, false);
697 (format!("{}^(1/{})", b_s, a), PREC_POWER)
698 }
699 Symbol::Log => (format!("Log[{}, {}]", a, b), PREC_ATOM),
700 Symbol::Atan2 => (format!("ArcTan[{}, {}]", b, a), PREC_ATOM),
701 _ => unreachable!(),
702 };
703 stack.push((result, prec));
704 }
705 }
706 }
707
708 stack
709 .pop()
710 .map(|(s, _)| s)
711 .unwrap_or_else(|| "?".to_string())
712 }
713
714 pub fn to_infix_sympy(&self) -> String {
715 const PREC_ATOM: u8 = 100;
716 const PREC_POWER: u8 = 9;
717 const PREC_UNARY: u8 = 8;
718 const PREC_MUL: u8 = 6;
719 const PREC_ADD: u8 = 4;
720
721 fn needs_paren(
722 parent_prec: u8,
723 child_prec: u8,
724 is_right_assoc: bool,
725 is_right_operand: bool,
726 ) -> bool {
727 if child_prec < parent_prec {
728 return true;
729 }
730 if is_right_assoc && is_right_operand && child_prec == parent_prec {
731 return true;
732 }
733 false
734 }
735
736 fn maybe_paren(
737 s: &str,
738 prec: u8,
739 parent_prec: u8,
740 is_right_assoc: bool,
741 is_right: bool,
742 ) -> String {
743 if needs_paren(parent_prec, prec, is_right_assoc, is_right) {
744 format!("({})", s)
745 } else {
746 s.to_string()
747 }
748 }
749
750 let mut stack: Vec<(String, u8)> = Vec::new();
751
752 for &sym in &self.symbols {
753 match sym.seft() {
754 Seft::A => {
755 let s = match sym {
756 Symbol::Pi => "pi",
757 Symbol::E => "E",
758 Symbol::Phi => "GoldenRatio",
759 Symbol::Gamma => "EulerGamma",
760 Symbol::Apery => "zeta(3)",
761 Symbol::Catalan => "Catalan",
762 _ => "",
763 };
764 let name = if s.is_empty() {
765 sym.display_name()
766 } else {
767 s.to_string()
768 };
769 stack.push((name, PREC_ATOM));
770 }
771 Seft::B => {
772 let (arg, arg_prec) = stack
773 .pop()
774 .expect("stack underflow in to_infix: expression is not valid postfix");
775 let result = match sym {
776 Symbol::Neg => {
777 let s = maybe_paren(&arg, arg_prec, PREC_UNARY, false, false);
778 format!("-{}", s)
779 }
780 Symbol::Recip => {
781 let s = maybe_paren(&arg, arg_prec, PREC_MUL, false, false);
782 format!("1/{}", s)
783 }
784 Symbol::Sqrt => format!("sqrt({})", arg),
785 Symbol::Square => {
786 let s = maybe_paren(&arg, arg_prec, PREC_POWER, false, false);
787 format!("{}**2", s)
788 }
789 Symbol::Ln => format!("log({})", arg),
790 Symbol::Exp => format!("exp({})", arg),
791 Symbol::SinPi => format!("sin(pi*{})", arg),
792 Symbol::CosPi => format!("cos(pi*{})", arg),
793 Symbol::TanPi => format!("tan(pi*{})", arg),
794 Symbol::LambertW => format!("lambertw({})", arg),
795 Symbol::UserFunction0
796 | Symbol::UserFunction1
797 | Symbol::UserFunction2
798 | Symbol::UserFunction3
799 | Symbol::UserFunction4
800 | Symbol::UserFunction5
801 | Symbol::UserFunction6
802 | Symbol::UserFunction7
803 | Symbol::UserFunction8
804 | Symbol::UserFunction9
805 | Symbol::UserFunction10
806 | Symbol::UserFunction11
807 | Symbol::UserFunction12
808 | Symbol::UserFunction13
809 | Symbol::UserFunction14
810 | Symbol::UserFunction15 => format!("{}({})", sym.display_name(), arg),
811 _ => "?".to_string(),
812 };
813 stack.push((result, PREC_ATOM));
814 }
815 Seft::C => {
816 let (b, b_prec) = stack
817 .pop()
818 .expect("stack underflow in to_infix: expression is not valid postfix");
819 let (a, a_prec) = stack
820 .pop()
821 .expect("stack underflow in to_infix: expression is not valid postfix");
822 let (result, prec) = match sym {
823 Symbol::Add => {
824 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
825 (format!("{}+{}", a, b_s), PREC_ADD)
826 }
827 Symbol::Sub => {
828 let b_s = maybe_paren(&b, b_prec, PREC_ADD, false, true);
829 (format!("{}-{}", a, b_s), PREC_ADD)
830 }
831 Symbol::Mul => {
832 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
833 let b_s = maybe_paren(&b, b_prec, PREC_MUL, false, true);
834 (format!("{}*{}", a_s, b_s), PREC_MUL)
835 }
836 Symbol::Div => {
837 let a_s = maybe_paren(&a, a_prec, PREC_MUL, false, false);
838 let b_s = maybe_paren(&b, b_prec, PREC_MUL + 1, false, true);
839 (format!("{}/{}", a_s, b_s), PREC_MUL)
840 }
841 Symbol::Pow => {
842 let a_s = maybe_paren(&a, a_prec, PREC_POWER, true, false);
843 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, true);
844 (format!("{}**{}", a_s, b_s), PREC_POWER)
845 }
846 Symbol::Root => {
847 let b_s = maybe_paren(&b, b_prec, PREC_POWER, true, false);
848 (format!("{}**(1/{})", b_s, a), PREC_POWER)
849 }
850 Symbol::Log => (format!("log({}, {})", b, a), PREC_ATOM),
851 Symbol::Atan2 => (format!("atan2({}, {})", a, b), PREC_ATOM),
852 _ => unreachable!(),
853 };
854 stack.push((result, prec));
855 }
856 }
857 }
858
859 stack
860 .pop()
861 .map(|(s, _)| s)
862 .unwrap_or_else(|| "?".to_string())
863 }
864}
865
866impl Default for Expression {
867 fn default() -> Self {
868 Self::new()
869 }
870}
871
872impl fmt::Display for Expression {
873 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
874 write!(f, "{}", self.to_infix())
875 }
876}
877
878impl fmt::Debug for Expression {
879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880 write!(f, "Expr[{}] = {}", self.to_postfix(), self.to_infix())
881 }
882}
883
884#[derive(Clone, Debug)]
886pub struct EvaluatedExpr {
887 pub expr: Expression,
889 pub value: f64,
891 pub derivative: f64,
893 #[allow(dead_code)]
898 pub num_type: NumType,
899}
900
901impl EvaluatedExpr {
902 pub fn new(expr: Expression, value: f64, derivative: f64, num_type: NumType) -> Self {
903 Self {
904 expr,
905 value,
906 derivative,
907 num_type,
908 }
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use super::*;
915
916 #[test]
917 fn test_parse_expression() {
918 let expr = Expression::parse("32+").unwrap();
919 assert_eq!(expr.len(), 3);
920 assert_eq!(expr.to_postfix(), "32+");
921 assert!(!expr.contains_x());
922 }
923
924 #[test]
925 fn test_expression_validity() {
926 assert!(Expression::parse("32+").unwrap().is_valid());
928
929 assert!(Expression::parse("xs").unwrap().is_valid());
931
932 assert!(Expression::parse("3+").is_none());
934
935 assert!(Expression::parse("32").is_none());
937 }
938
939 #[test]
940 fn test_infix_conversion() {
941 assert_eq!(Expression::parse("32+").unwrap().to_infix(), "3+2");
942 assert_eq!(Expression::parse("32*").unwrap().to_infix(), "3*2");
943 assert_eq!(Expression::parse("xs").unwrap().to_infix(), "x^2");
944 assert_eq!(Expression::parse("xq").unwrap().to_infix(), "sqrt(x)");
945 assert_eq!(Expression::parse("32+5*").unwrap().to_infix(), "(3+2)*5");
946 }
947
948 #[test]
949 fn test_complexity() {
950 let expr = Expression::parse("xs").unwrap(); assert_eq!(expr.complexity(), 15 + 9);
953 }
954
955 #[test]
956 fn test_tree_depth_atom() {
957 assert_eq!(Expression::parse("x").unwrap().tree_depth(), 1);
959 assert_eq!(Expression::parse("1").unwrap().tree_depth(), 1);
960 assert_eq!(Expression::parse("p").unwrap().tree_depth(), 1); }
962
963 #[test]
964 fn test_tree_depth_unary() {
965 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); }
970
971 #[test]
972 fn test_tree_depth_binary() {
973 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); }
978
979 #[test]
980 fn test_tree_depth_nested() {
981 assert_eq!(Expression::parse("xqq").unwrap().tree_depth(), 3); assert_eq!(Expression::parse("12+34+*").unwrap().tree_depth(), 3); }
985
986 #[test]
987 fn test_tree_depth_empty() {
988 assert_eq!(Expression::new().tree_depth(), 0);
990 }
991
992 #[test]
993 fn test_tree_depth_malformed() {
994 assert_eq!(
996 Expression::from_symbols(&[Symbol::X, Symbol::One]).tree_depth(),
997 0
998 );
999 }
1000
1001 #[test]
1002 fn test_operator_count_atom() {
1003 assert_eq!(Expression::parse("x").unwrap().operator_count(), 0);
1005 assert_eq!(Expression::parse("1").unwrap().operator_count(), 0);
1006 assert_eq!(Expression::parse("p").unwrap().operator_count(), 0);
1007 }
1008
1009 #[test]
1010 fn test_operator_count_unary() {
1011 assert_eq!(Expression::parse("xq").unwrap().operator_count(), 1);
1013 assert_eq!(Expression::parse("xs").unwrap().operator_count(), 1);
1014 assert_eq!(Expression::parse("xn").unwrap().operator_count(), 1);
1015 }
1016
1017 #[test]
1018 fn test_operator_count_binary() {
1019 assert_eq!(Expression::parse("12+").unwrap().operator_count(), 1);
1021 assert_eq!(Expression::parse("x2*").unwrap().operator_count(), 1);
1022 }
1023
1024 #[test]
1025 fn test_operator_count_complex() {
1026 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); }
1031
1032 #[test]
1033 fn test_operator_count_empty() {
1034 assert_eq!(Expression::new().operator_count(), 0);
1035 }
1036
1037 #[test]
1038 fn test_push_pop_complexity_saturating() {
1039 let mut expr = Expression::new();
1040
1041 for _ in 0..1000 {
1043 expr.push(Symbol::X);
1044 }
1045 assert!(expr.complexity() < u32::MAX);
1047
1048 for _ in 0..1000 {
1050 expr.pop();
1051 }
1052 assert_eq!(expr.complexity(), 0);
1054 }
1055
1056 #[test]
1060 #[should_panic(expected = "stack underflow in to_infix")]
1061 fn test_to_infix_panics_on_malformed_expression() {
1062 let expr = Expression::from_symbols(&[Symbol::Add]);
1065 let _ = expr.to_infix();
1066 }
1067
1068 #[test]
1069 fn test_try_to_infix_returns_err_on_malformed_expression() {
1070 let expr = Expression::from_symbols(&[Symbol::Add]);
1073 let result = expr.try_to_infix();
1074 assert!(
1075 result.is_err(),
1076 "try_to_infix on malformed expression should return Err, got Ok({:?})",
1077 result.ok()
1078 );
1079 }
1080
1081 #[test]
1082 fn test_try_to_infix_succeeds_on_valid_expression() {
1083 let expr = Expression::parse("32+").unwrap();
1084 let result = expr.try_to_infix();
1085 assert_eq!(result.unwrap(), "3+2");
1086 }
1087}