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