1use indexmap::IndexMap;
2use lazy_static::lazy_static;
3use regex::{Captures, Regex};
4use std::{num::ParseIntError, str::FromStr, sync::LazyLock};
5
6use crate::{expr::*, symbol};
7
8use thiserror::Error;
9
10use crate::{Equation, Expr, Integer};
11
12#[derive(Error, Debug, PartialEq)]
13pub enum ParseExprError {
14 #[error("bad equation: {0}")]
15 BadEquation(#[from] ParseEquationError),
16 #[error("parse integer: {0}")]
17 BadInt(#[from] ParseIntegerError),
18 #[error("parse symbol: {0}")]
19 BadSymbol(#[from] ParseSymbolError),
20 #[error("bad addition: {0}")]
21 BadAdd(#[from] ParseAddError),
22 #[error("bad multiplication: {0}")]
23 BadMul(#[from] ParseMulError),
24 #[error("bracket mismatch: '{0}' and '{1}'")]
25 BracketMismatch(char, char),
26 #[error("bad function: {0}")]
27 BadFunction(#[from] ParseFunctionError),
28 #[error("invalid pow: {0}")]
29 InvalidPow(#[from] ParsePowError),
30 #[error("invalid diffentiation: {0}")]
31 InvalidDiff(#[from] ParseDiffError),
32 #[error("empty expression")]
33 EmptyExpr,
34}
35
36#[derive(Error, Debug, PartialEq)]
37pub enum ParseEquationError {
38 #[error("wrong number of operands: {0}, expected: 2")]
39 WrongNumberOfOperands(usize),
40 #[error("empty operand")]
41 EmptyOperand,
42 #[error("invalid lhs: {0}")]
43 InvalidLhs(Box<ParseExprError>),
44 #[error("invalid rhs: {0}")]
45 InvalidRhs(Box<ParseExprError>),
46}
47
48#[derive(Debug, Error, PartialEq)]
49#[error("failed to parse integer: {0}")]
50pub struct ParseIntegerError(String, #[source] ParseIntError);
51
52impl FromStr for Integer {
53 type Err = ParseIntegerError;
54
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
56 Ok(Integer {
57 value: s.parse().map_err(|e| ParseIntegerError(s.to_string(), e))?,
58 })
59 }
60}
61
62impl FromStr for Box<dyn Expr> {
63 type Err = ParseExprError;
64
65 fn from_str(s: &str) -> Result<Self, Self::Err> {
66 parse_expr(s)
67 }
68}
69
70impl FromStr for Equation {
71 type Err = ParseEquationError;
72
73 fn from_str(s: &str) -> Result<Self, Self::Err> {
74 let equal_pieces: Vec<_> = s.split('=').map(|s| s.trim()).collect();
75 if equal_pieces.len() != 2 {
76 Err(ParseEquationError::WrongNumberOfOperands(
77 equal_pieces.len(),
78 ))?
79 }
80
81 if equal_pieces.iter().any(|s| s.is_empty()) {
82 Err(ParseEquationError::EmptyOperand)?
83 }
84
85 Ok(Equation {
86 lhs: equal_pieces[0]
87 .parse()
88 .map_err(|e| ParseEquationError::InvalidLhs(Box::new(e)))?,
89 rhs: equal_pieces[1]
90 .parse()
91 .map_err(|e| ParseEquationError::InvalidRhs(Box::new(e)))?,
92 })
93 }
94}
95
96#[derive(Error, Debug, PartialEq)]
97pub enum ParseSymbolError {}
98
99impl FromStr for Symbol {
100 type Err = ParseSymbolError;
101
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 Ok(Symbol::new(s))
104 }
105}
106
107#[derive(Error, Debug, PartialEq)]
108pub enum ParseAddError {
109 #[error("bad operand: {0}")]
110 BadOperand(String, #[source] Box<ParseExprError>),
111}
112
113impl FromStr for Add {
114 type Err = ParseAddError;
115
116 fn from_str(s: &str) -> Result<Self, Self::Err> {
117 Ok(Add::new_v2(
118 split_root(s, &['+', '-'])
119 .map(|(prev, piece)| -> Result<Box<dyn Expr>, ParseAddError> {
120 let mut op: Box<dyn Expr> = piece
121 .parse()
122 .map_err(|e| ParseAddError::BadOperand(piece.into(), Box::new(e)))?;
123 if let Some('-') = prev {
124 op = -op;
125 }
126 Ok(op)
127 })
128 .collect::<Result<_, _>>()?,
129 ))
130 }
131}
132
133#[derive(Error, Debug, PartialEq)]
134pub enum ParseMulError {
135 #[error("bad operand: {0}")]
136 BadOperand(String, #[source] Box<ParseExprError>),
137}
138
139impl FromStr for Mul {
140 type Err = ParseMulError;
141
142 fn from_str(s: &str) -> Result<Self, Self::Err> {
143 let mut ops = Vec::new();
144 for (prev, piece) in split_root(s, &['*', '/']) {
145 let mut op: Box<dyn Expr> = piece
146 .parse()
147 .map_err(|e| ParseMulError::BadOperand(piece.into(), Box::new(e)))?;
148 if let Some('/') = prev {
149 op = op.ipow(-1);
150 }
151
152 if let Some(Mul { operands }) = op.as_mul().cloned() {
153 for op in operands {
154 ops.push(op);
155 }
156 } else {
157 ops.push(op)
158 }
159 }
160 Ok(Mul { operands: ops })
161 }
162}
163
164const func_pattern: &str = r"^(\w+)\((.*?)\)$";
165
166lazy_static! {
167 static ref func_re: Regex = Regex::new(func_pattern).unwrap();
168}
169
170#[derive(Error, Debug, PartialEq)]
171pub enum ParseFunctionError {
172 #[error("bad args")]
173 BadArgs,
174 #[error("wrong number of arguments for {0}: {1}, expected: {2}")]
175 BadArgCount(String, usize, String),
176 #[error("invalid function expression: {0}")]
177 InvalidFuncExpr(Box<ParseExprError>),
178 #[error("invalid order format: {0}, {1}")]
179 InvalidOrderFormat(String, ParseIntError),
180 #[error("invalid argument: {0}")]
181 InvalidArg(String, #[source] Box<ParseExprError>),
182 #[error("invalid differential expression")]
183 InvalidDiff(String, #[source] ParseDiffError),
184}
185
186static D_DVAR_RE: LazyLock<Regex> = LazyLock::new(|| {
187 Regex::new(r"^[d∂]\^?([\d⁰¹²³⁴⁵⁶⁷⁸⁹]*)\s*[\/_]\s*[d∂]\(?(\w+?)\)?\^?([\d⁰¹²³⁴⁵⁶⁷⁸]*)$").unwrap()
188});
189
190static DNVAR_RE: LazyLock<Regex> =
191 LazyLock::new(|| Regex::new(r"^[d∂]\^?(?:([\d⁰¹²³⁴⁵⁶⁷⁸⁹]+))?([A-Za-z_])$").unwrap());
192
193static SUB_DNVAR: LazyLock<Regex> =
194 LazyLock::new(|| Regex::new(r"^[d∂]\^?(?:([\d⁰¹²³⁴⁵⁶⁷⁸⁹]+))?([A-Za-z_])\((.*)\)$").unwrap());
195
196pub fn parse_function(name: &str, args: &str) -> Result<Box<dyn Expr>, ParseFunctionError> {
197 let args: Vec<_> = args.split(",").map(|arg| arg.trim()).collect();
198
199 if let Some(captures) = DNVAR_RE.captures(name) {
201 let var = &captures[2];
202 let order = captures.get(1).map_or("1", |o| o.as_str());
203 let order = order.parse().map_err(|e| {
204 ParseFunctionError::InvalidDiff(
205 name.to_string(),
206 ParseDiffError::InvalidNumOrderFormat(order.to_string(), e),
207 )
208 })?;
209
210 let mut var_orders: IndexMap<Symbol, usize> = IndexMap::new();
211 var_orders.insert(
212 Symbol {
213 name: var.to_string(),
214 },
215 order,
216 );
217
218 let mut f = args[0].to_string();
219
220 while let Some(captures) = SUB_DNVAR.captures(&f) {
221 let var = captures[2].to_string();
222 let var_order = captures.get(1).map_or("1", |o| o.as_str());
223 let var_order: usize = var_order.parse().map_err(|e| {
224 ParseFunctionError::InvalidDiff(
225 name.to_string(),
226 ParseDiffError::InvalidNumOrderFormat(var_order.to_string(), e),
227 )
228 })?;
229 f = captures[3].to_string();
230 let order = var_orders.entry(Symbol { name: var }).or_insert(0);
231 *order += var_order;
232 }
233
234 return Ok(Box::new(Diff::new_v2(
235 f.parse()
236 .map_err(|e| ParseFunctionError::InvalidFuncExpr(Box::new(e)))?,
237 var_orders,
238 )));
239 }
240
241 if let Some(captures) = D_DVAR_RE.captures(name) {
242 let num_order = &captures[1];
243 let den_order = &captures[3];
244 let var = Symbol::new(&captures[2]);
245 let num_order: usize = num_order
246 .parse()
247 .map_err(|e| ParseFunctionError::InvalidOrderFormat(num_order.to_string(), e))?;
248 let den_order: usize = den_order
249 .parse()
250 .map_err(|e| ParseFunctionError::InvalidOrderFormat(den_order.to_string(), e))?;
251
252 if num_order != den_order {
253 Err(ParseFunctionError::InvalidDiff(
254 name.to_string(),
255 ParseDiffError::OrderMismatch(num_order, den_order),
256 ))?
257 }
258
259 if args.len() != 1 {
260 Err(ParseFunctionError::BadArgCount(
261 name.to_string(),
262 args.len(),
263 "1".to_string(),
264 ))?
265 }
266
267 let expr = parse_expr(args[0]).map_err(|e| {
268 ParseFunctionError::InvalidDiff(
269 args[0].to_string(),
270 ParseDiffError::BadExpr(Box::new(e)),
271 )
272 })?;
273 return Ok(Box::new(Diff::new_move(expr, vec![var; num_order])));
274 }
275
276 Ok(match name {
277 "laplacian" => {
278 let laplacian = symbol!("laplacian");
279 let f = parse_expr(args[0])
280 .map_err(|e| ParseFunctionError::InvalidFuncExpr(Box::new(e)))?;
281
282 laplacian * f
283 }
284 "diff" => {
285 let n_args = args.len();
286 if n_args < 2 || n_args > 3 {
287 Err(ParseFunctionError::BadArgCount(
288 name.to_string(),
289 n_args,
290 "2 or 3".to_string(),
291 ))?
292 }
293 let f = parse_expr(args[0])
294 .map_err(|e| ParseFunctionError::InvalidFuncExpr(Box::new(e)))?;
295 let order = if n_args == 3 {
296 args[2]
297 .parse()
298 .map_err(|e| ParseFunctionError::InvalidOrderFormat(args[2].to_string(), e))?
299 } else {
300 1
301 };
302 f.diff(args[1], order)
303 }
304 _ => {
305 let args: Result<Vec<Box<dyn Expr>>, ParseFunctionError> = args
306 .into_iter()
307 .map(|a| -> Result<Box<dyn Expr>, ParseFunctionError> {
308 Ok(a.parse()
309 .map_err(|e| ParseFunctionError::InvalidArg(a.into(), Box::new(e)))?)
310 })
311 .collect();
312
313 Func::new_move_box(name.to_string(), args?)
314 }
315 })
316}
317
318#[derive(Error, Debug, PartialEq)]
319pub enum ParsePowError {
320 #[error("invalid pow format: {0}, expected 'base^exponent'")]
321 InvalidFormat(String),
322 #[error("invalid expression for base: {0}, {1}")]
323 InvalidBase(String, Box<ParseExprError>),
324 #[error("invalid expression for exponent: {0}, {1}")]
325 InvalidExponent(String, Box<ParseExprError>),
326}
327
328impl FromStr for expr::Pow {
329 type Err = ParsePowError;
330
331 fn from_str(s: &str) -> Result<Self, Self::Err> {
332 let pieces: Vec<_> = s.split("^").collect();
333 if pieces.len() != 2 {
334 Err(ParsePowError::InvalidFormat(s.to_string()))?
335 }
336 let mut parsed: Vec<_> = pieces.iter().map(|e| parse_expr(e)).collect();
337 let exponent = parsed
338 .pop()
339 .unwrap()
340 .map_err(|err| ParsePowError::InvalidExponent(pieces[1].to_string(), Box::new(err)))?;
341 let base = parsed
342 .pop()
343 .unwrap()
344 .map_err(|err| ParsePowError::InvalidBase(pieces[0].to_string(), Box::new(err)))?;
345 Ok(Pow::new_move(base, exponent))
346 }
347}
348
349lazy_static! {
350 static ref diff_re: Regex = Regex::new(
351 r"^[d∂]\^?([\d⁰¹²³⁴⁵⁶⁷⁸⁹]*)\(?(.+?)\)?\s*[/_]\s*[d∂]\(?(\w+?)\)?\^?([\d⁰¹²³⁴⁵⁶⁷⁸]*)$"
352 )
353 .unwrap();
354}
355
356#[derive(Debug, Error, PartialEq)]
357pub enum ParseDiffError {
358 #[error("invalid diffentiation format: {0}, expected 'd^n(expr) / d(var)^n'")]
359 InvalidFormat(String),
360 #[error("invalid differentiated expression")]
361 BadExpr(#[from] Box<ParseExprError>),
362 #[error("invalid order format on numerator: {0}, {1}")]
363 InvalidNumOrderFormat(String, ParseIntError),
364 #[error("invalid order format on denominator: {0}, {1}")]
365 InvalidDenOrderFormat(String, ParseIntError),
366 #[error("order mismatch: numerator: {0}, denominator: {1}")]
367 OrderMismatch(usize, usize),
368}
369
370impl FromStr for Diff {
371 type Err = ParseDiffError;
372
373 fn from_str(s: &str) -> Result<Self, Self::Err> {
374 let captures = diff_re
375 .captures(s)
376 .ok_or_else(|| ParseDiffError::InvalidFormat(s.to_string()))?;
377 captures.try_into()
378 }
379}
380
381impl TryFrom<Captures<'_>> for Diff {
382 type Error = ParseDiffError;
383
384 fn try_from(value: Captures<'_>) -> Result<Self, Self::Error> {
385 let num_order = &value[1];
386 let den_order = &value[4];
387 let num_order: usize = if num_order == "" {
388 1
389 } else {
390 value[1]
391 .parse()
392 .map_err(|e| ParseDiffError::InvalidNumOrderFormat(value[1].to_string(), e))?
393 };
394 let den_order: usize = if den_order == "" {
395 1
396 } else {
397 value[4]
398 .parse()
399 .map_err(|e| ParseDiffError::InvalidDenOrderFormat(value[4].to_string(), e))?
400 };
401 let expr = parse_expr(&value[2]).map_err(|e| ParseDiffError::BadExpr(Box::new(e)))?;
402 let var = Symbol::new(&value[3]);
403
404 if num_order != den_order {
405 Err(ParseDiffError::OrderMismatch(num_order, den_order))?
406 }
407
408 Ok(Diff::new_move(expr, vec![var; num_order]))
409 }
410}
411
412#[derive(Debug, Error, PartialEq)]
413pub enum ParseRationalError {
414 #[error("invalid rational format: {0}, expected 'numerator / denominator'")]
415 InvalidFormat(String),
416 #[error("invalid numerator: {0}")]
417 InvalidNumerator(String),
418 #[error("invalid denominator: {0}")]
419 InvalidDenominator(String),
420}
421
422static RATIONAL_RE: LazyLock<Regex> =
423 LazyLock::new(|| Regex::new(r"^\s*?([^/\s]+?)\s*?(?:/\s*?([^/\s]*?)\s*?)?$").unwrap());
424
425impl FromStr for Rational {
426 type Err = ParseRationalError;
427
428 fn from_str(s: &str) -> Result<Self, Self::Err> {
429 let captures = RATIONAL_RE
430 .captures(s)
431 .ok_or_else(|| ParseRationalError::InvalidFormat(s.to_string()))?;
432 let num = &captures[1];
433
434 let num: Rational = (if let Ok(num) = num.parse::<i32>() {
435 Ok(num.into())
436 } else if let Ok(num) = num.parse::<f64>() {
437 Ok(Rational::from_float(num))
438 } else {
439 Err(ParseRationalError::InvalidNumerator(num.to_string()))
440 })?;
441
442 let den = captures.get(2);
443
444 let den = den.map(|den| -> Result<_, _> {
445 if let Ok(den) = den.as_str().parse::<i32>() {
446 Ok(den.into())
447 } else if let Ok(den) = den.as_str().parse::<f64>() {
448 Ok(Rational::from_float(den))
449 } else {
450 Err(ParseRationalError::InvalidDenominator(
451 den.as_str().to_string(),
452 ))
453 }
454 });
455
456 let den: Rational = if let Some(den) = den { den? } else { 1.into() };
457
458 Ok(num / den)
459 }
460}
461
462pub fn are_brackets_valid(s: &str) -> bool {
466 let mut stack: Vec<usize> = Vec::new();
467
468 for c in s.chars() {
469 if let Some(i) = openers.iter().position(|opener| opener == &c) {
470 stack.push(i);
471 } else if let Some(i) = closers.iter().position(|closer| closer == &c) {
472 if stack.pop() != Some(i) {
473 return false;
474 }
475 }
476 }
477 stack.is_empty()
478}
479
480pub fn parse_expr(s: &str) -> Result<Box<dyn Expr>, ParseExprError> {
481 let s = s.trim();
482 if s.len() == 0 {
483 Err(ParseExprError::EmptyExpr)?
484 }
485 Ok(if s.split("=").collect::<Vec<_>>().len() >= 2 {
486 Box::new(s.parse::<Equation>()?)
487 }
488 else if let Some(captured_func) = func_re.captures(s)
490 && are_brackets_valid(&captured_func[2])
491 {
492 return Ok(parse_function(&captured_func[1], &captured_func[2])?);
493 }
494 else if s
496 .chars()
497 .enumerate()
498 .all(|(i, c)| c.is_numeric() || i == 0 && c == '-')
499 {
500 Box::new(s.parse::<Integer>()?)
501 }
502 else if let Ok(r) = s.parse::<Rational>() {
504 Box::new(r)
505 }
506 else if let Some((_, add_piece)) = split_root(s, &['+', '-']).next()
508 && add_piece.len() != s.len()
509 {
510 Box::new(s.parse::<Add>()?)
511 }
512 else if let Some(captured_diff) = diff_re.captures(s) {
514 Box::new(TryInto::<Diff>::try_into(captured_diff)?)
515 }
516 else if let Some((_, mul_piece)) = split_root(s, &['*', '/']).next()
518 && mul_piece.len() != s.len()
519 {
520 Box::new(s.parse::<Mul>()?)
521 }
522 else if s.len() > 0
524 && let Some(first) = s.chars().next()
525 && let Some(i_opener) = openers
526 .iter()
527 .enumerate()
528 .find_map(|(i, opener)| if opener == &first { Some(i) } else { None })
529 && let Some(last) = s.chars().last()
530 && let Some(i_closer) = closers
531 .iter()
532 .enumerate()
533 .find_map(|(i, closer)| if closer == &last { Some(i) } else { None })
534 && i_opener == i_closer
535 {
536 return parse_expr(&s[1..s.len() - 1]);
543 }
544 else if s.contains("^") {
546 Box::new(s.parse::<Pow>()?)
547 }
548 else {
550 Box::new(s.parse::<Symbol>()?)
551 })
552}
553
554const openers: [char; 3] = ['(', '[', '{'];
555const closers: [char; 3] = [')', ']', '}'];
556
557pub struct RootSplitter<'a, 'b> {
558 s: &'a str,
559 patterns: &'b [char],
560 position: usize,
561 prev_splitter: Option<char>,
562 depth: i32,
563 begin: usize,
564}
565
566impl<'a, 'b> Iterator for RootSplitter<'a, 'b> {
567 type Item = (Option<char>, &'a str);
568
569 fn next(&mut self) -> Option<Self::Item> {
570 for (i, c) in self.s[self.position..].char_indices() {
571 let abs_i = self.position + i; if openers.contains(&c) {
574 self.depth += 1;
575 } else if closers.contains(&c) {
576 self.depth -= 1;
577 } else if self.depth == 0 && self.patterns.contains(&c) {
578 let part = &self.s[self.begin..abs_i];
579 if part.trim().is_empty() {
581 continue;
582 }
583 self.begin = abs_i + 1; self.position = abs_i + 1;
585 let res = (self.prev_splitter, part.trim());
586 self.prev_splitter = Some(c);
587 return Some(res);
588 }
589 }
590
591 if self.begin < self.s.len() {
593 let part = &self.s[self.begin..];
594 self.begin = self.s.len(); return Some((self.prev_splitter, part.trim()));
596 }
597
598 None }
600}
601
602pub fn split_root<'a, 'b>(s: &'a str, patterns: &'b [char]) -> RootSplitter<'a, 'b> {
603 RootSplitter {
604 s,
605 prev_splitter: None,
606 patterns,
607 position: 0,
608 depth: 0,
609 begin: 0,
610 }
611}
612
613#[cfg(test)]
614mod tests {
615 use super::*;
616 use crate::symbols;
617
618 #[test]
619 fn test_root_splitter() {
620 assert_eq!(
621 split_root("a + (b + c) + 2 - (4)", &['+', '-']).collect::<Vec<_>>(),
622 vec![
623 (None, "a"),
624 (Some('+'), "(b + c)"),
625 (Some('+'), "2"),
626 (Some('-'), "(4)")
627 ]
628 )
629 }
630
631 #[test]
632 fn test_parse_zero() {
633 let expr = parse_expr("0").unwrap();
634 assert_eq!(expr.srepr(), "Integer(0)")
635 }
636
637 #[test]
638 fn test_parse_int() {
639 let expr = parse_expr("1").unwrap();
640 assert_eq!(expr.srepr(), "Integer(1)")
641 }
642
643 #[test]
644 fn test_parse_neg_int() {
645 let expr = parse_expr("-128").unwrap();
646 assert_eq!(expr.srepr(), "Integer(-128)")
647 }
648
649 #[test]
650 fn test_parse_laplacian() {
651 let expr = parse_expr("laplacian").unwrap();
652 assert_eq!(expr.srepr(), "Symbol(Δ)")
653 }
654
655 #[test]
656 fn test_parse_x() {
657 let expr = parse_expr("x").unwrap();
658 assert_eq!(expr.srepr(), "Symbol(x)")
659 }
660
661 #[test]
662 fn test_parse_invalid_equation() {
663 let res = parse_expr("1 ==");
664 assert_eq!(
665 res,
666 Err(ParseExprError::BadEquation(
667 ParseEquationError::WrongNumberOfOperands(3)
668 ))
669 )
670 }
671
672 #[test]
673 fn test_parse_bad_eq_empty_op() {
674 let res = parse_expr("1 =");
675 assert_eq!(
676 res,
677 Err(ParseExprError::BadEquation(
678 ParseEquationError::EmptyOperand
679 ))
680 )
681 }
682
683 #[test]
684 fn parse_valid_basic_eq() {
685 let res = parse_expr("1 = 2").unwrap();
686 assert_eq!(res.srepr(), "Eq(Integer(1), Integer(2))")
687 }
688
689 #[test]
690 fn parse_add() {
691 let res = parse_expr("1 + 2").unwrap();
692 assert_eq!(res.srepr(), "Add(Integer(1), Integer(2))")
693 }
694
695 #[test]
696 fn parse_sub() {
697 let res = parse_expr("1 - x + 4").unwrap();
698 assert_eq!(
699 res.srepr(),
700 "Add(Integer(1), Mul(Integer(-1), Symbol(x)), Integer(4))"
701 )
702 }
703
704 #[test]
705 fn parse_mul() {
706 let res = parse_expr("1 * x * 4").unwrap();
707 assert_eq!(res.srepr(), "Mul(Integer(1), Symbol(x), Integer(4))")
708 }
709
710 #[test]
711 fn parse_div() {
712 let res = parse_expr("1 / x").unwrap();
713 assert_eq!(res.srepr(), "Mul(Integer(1), Pow(Symbol(x), Integer(-1)))")
714 }
715
716 #[test]
717 fn parse_deep_add() {
718 let res = parse_expr("1 + (1 + 2) * 3 + 4").unwrap();
719 assert_eq!(
720 res.srepr(),
721 "Add(Integer(1), Mul(Add(Integer(1), Integer(2)), Integer(3)), Integer(4))"
722 )
723 }
724
725 #[test]
726 fn parse_wave_eq() {
727 let res = parse_expr("diff(u, t, 2) - c^2 * laplacian * u = f").unwrap();
728 let [u, c, laplacian, f] = symbols!("u", "c", "laplacian", "f");
729 let expected = Equation::new_box(u.diff("t", 2) - c.ipow(2) * laplacian * u, f.clone_box());
730 assert_eq!(res, expected)
731 }
732
733 #[test]
734 fn parse_2d_wave_eq() {
735 let res = parse_expr("d2u/dt^2 = c^2 * (d2u/dx2 + d2u/dy2) + source").unwrap();
736 let [u, c, source] = symbols!("u", "c", "source");
737 let expected = Equation::new_box(
738 u.diff("t", 2),
739 c * c * (u.diff("x", 2) + u.diff("y", 2)) + source.clone_box(),
740 );
741 assert_eq!(res, expected)
742 }
743
744 #[test]
745 fn parse_diff_complex() {
746 let res: Box<dyn Expr> = "d^2(2*x*t + t^2 - t)/dt^2".parse().unwrap();
747 let [x, t] = symbols!("x", "t");
748 let expected = (Integer::new_box(2) * x * t + t * t - t.clone_box()).diff("t", 2);
749 assert_eq!(res, expected)
750 }
751
752 #[test]
753 fn parse_dx_syntax() {
754 let res = parse_expr("dx(dx(x))").unwrap();
755 let [x] = symbols!("x");
756 let expected = x.diff("x", 2);
757 assert_eq!(res, expected)
758 }
759
760 #[test]
761 fn parse_dx_dy_syntax() {
762 let res = parse_expr("dx(dy(x))").unwrap();
763 let [x, y] = symbols!("x", "y");
764 let expected = Diff::new(&x.clone_box(), &[x.clone_box(), y.clone_box()]);
765 assert_eq!(res, expected)
766 }
767
768 #[test]
769 fn parse_d2_dt2_syntax() {
770 let res = parse_expr("d2_dt2(u)").unwrap();
771 let [u] = symbols!("u");
772 let expected = u.diff("t", 2);
773 assert_eq!(res, expected)
774 }
775
776 #[test]
777 fn parse_d2u_dt2_syntax() {
778 let res = parse_expr("d2u_dt2").unwrap();
779 let [u] = symbols!("u");
780 let expected = u.diff("t", 2);
781 assert_eq!(res, expected)
782 }
783
784 #[test]
785 fn parse_gaussian_pulse() {
786 let res = parse_expr("exp(-100*((x-5)^2 + (y-5)^2))").unwrap();
787 let [x, y] = symbols!("x", "y");
788
789 let expected = Func::new_move_box(
790 "exp".into(),
791 vec![
792 Integer::new_box(-100)
793 * ((x - Integer::new_box(5).get_ref()).ipow(2)
794 + (y - Integer::new_box(5).get_ref()).ipow(2)),
795 ],
796 );
797 assert_eq!(res.get_ref(), expected.get_ref())
798 }
799
800 #[test]
801 fn parse_brackets_sum() {
802 let res = parse_expr("(1 + 2) + (3 + 4)").unwrap();
803 assert_eq!(
804 res.srepr(),
805 "Add(Add(Integer(1), Integer(2)), Add(Integer(3), Integer(4)))"
806 )
807 }
808
809 #[test]
810 fn parse_rational() {
811 let res = parse_expr("1/2").unwrap();
812 assert_eq!(res, Rational::new_box(1, 2));
813 }
814
815 #[test]
816 fn parse_float() {
817 let res = parse_expr("0.5").unwrap();
818 assert_eq!(res, Rational::new_box(1, 2));
819 }
820
821 #[test]
822 fn parse_d2t_syntax() {
823 let res = parse_expr("d2t(u)").unwrap();
824 let [u] = symbols!("u");
825 let expected = u.diff("t", 2);
826 assert_eq!(res, expected)
827 }
828
829 #[test]
830 fn parse_claud_wave_eq() {
831 let res = parse_expr("d2t(u) = c^2 * (d2x(u) + d2y(u))").unwrap();
832 let [u, c] = symbols!("u", "c");
833 let expected = Equation::new_box(
834 u.diff("t", 2),
835 c.ipow(2) * (u.diff("x", 2) + u.diff("y", 2)),
836 );
837 assert_eq!(res, expected)
838 }
839}