1use dec::Decimal;
2use serde::{Deserialize, Serialize};
3use std::io::{self, Read};
4
5const DECIMAL_PLACES_DEFAULT: usize = 27; const NAN: &str = "-0.0000000000000000000000000001"; pub type Dec = Decimal<DECIMAL_PLACES_DEFAULT>;
9
10#[derive(Debug, Deserialize, Serialize, Clone)]
11pub enum TreeNode {
12 Op(char, Box<TreeNode>, Box<TreeNode>),
13 Num(i32),
14 Var(String),
15 Fun(String, Box<TreeNode>),
16 Paren(Box<TreeNode>),
17 Empty,
18}
19
20#[derive(Debug, Deserialize, Serialize, Clone)]
22pub struct BinaryAlgebraicExpressionTree {
23 pub name: String,
24 pub root_node: TreeNode,
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct TestCase {
30 pub description: Option<String>,
32 pub examples: Vec<[String; 2]>,
34 pub solution: Vec<BinaryAlgebraicExpressionTree>,
35}
36
37impl Default for BinaryAlgebraicExpressionTree {
38 fn default() -> Self {
39 BinaryAlgebraicExpressionTree {
40 name: "NEW".to_string(),
41 root_node: parse_expression("1"),
42 }
43 }
44}
45
46pub fn read_terminal_input() {
48 let mut use_math_tricks = false;
49 let args: Vec<String> = std::env::args().skip(1).collect();
50 if args.len() == 1 && args[0].trim().starts_with("DECIMAL_PLACES(x)=") {
51 use_math_tricks = true;
52 }
53 let input = if args.len() == 1 && args[0].contains('\n') {
54 args[0]
55 .split('\n')
56 .map(|s| s.trim())
57 .filter(|s| !s.is_empty())
58 .map(|s| s.to_string())
59 .collect()
60 } else if args.is_empty() {
61 let mut buffer = String::new();
62 io::stdin().read_to_string(&mut buffer).unwrap();
63 buffer
64 .split('\n')
65 .map(|s| s.trim())
66 .filter(|s| !s.is_empty())
67 .map(|s| s.to_string())
68 .collect()
69 } else {
70 args
71 };
72 if input.is_empty() {
73 println!(
74 "Usage:\n single-variable-algebra-compiler FUNC1(x)=expr1 FUNC2(x)=expr2 ... FUNCN(INPUT)\nOR\n echo 'F(x)=4+4\nG(x)=F(x)*2\nG(1)' | single-variable-algebra-compiler"
75 );
76 return;
77 }
78 let mut trees = Vec::new();
79 for arg in input.iter().take(input.len() - 1) {
80 if let Some((name, expr)) = parse_function(arg) {
81 let tree = BinaryAlgebraicExpressionTree {
82 name: name.to_string(),
83 root_node: parse_expression(expr),
84 };
85 trees.push(tree);
86 } else {
87 println!("Invalid function definition: {arg}");
88 return;
89 }
90 }
91 if let Some((func_name, input_val)) = parse_function_call(input.last().unwrap()) {
92 if let Some(tree) = trees.iter().find(|t| t.name == func_name) {
93 let x: Dec = input_val.parse().unwrap_or_else(|_| {
94 println!("Invalid input value: {input_val}");
95 std::process::exit(1);
96 });
97 let result = apply_algebra_to_tree_node(&tree.root_node, &x, &trees, use_math_tricks);
98 println!("{}", trim2(result));
99 } else {
100 println!("Function {func_name} not defined");
101 }
102 } else {
103 println!("Invalid function call: {}", input.last().unwrap());
104 }
105}
106
107pub fn apply_algebra_to_tree_node(
109 node: &TreeNode,
110 x: &Dec,
111 tablets: &Vec<BinaryAlgebraicExpressionTree>,
112 use_math_tricks: bool,
113) -> Dec {
114 match node {
115 TreeNode::Num(n) => Dec::from(*n),
116 TreeNode::Var(s) => {
117 if s == "x" {
118 *x
119 } else {
120 s.parse::<Dec>()
121 .unwrap_or_else(|_| panic!("Unexpected variable: {s}"))
122 }
123 }
124 TreeNode::Fun(name, arg) => {
125 let arg_value = apply_algebra_to_tree_node(arg, x, tablets, use_math_tricks);
126 if name.as_str() == "GE0" && use_math_tricks {
127 math_trick::ge0(arg_value).parse().unwrap()
128 } else if name.as_str() == "IS0" && use_math_tricks {
129 math_trick::is0(arg_value).parse().unwrap()
130 } else if name.as_str() == "FLOOR1" && use_math_tricks {
131 math_trick::floor1(arg_value).parse().unwrap()
132 } else if name.as_str() == "LEFT" && use_math_tricks {
133 math_trick::left(arg_value.to_standard_notation_string())
134 .parse()
135 .unwrap()
136 } else {
137 let tablet = tablets
138 .iter()
139 .find(|tablet| name == &tablet.name)
140 .unwrap_or_else(|| panic!("There is no tree called {name}"));
141 apply_algebra_to_tree_node(&tablet.root_node, &arg_value, tablets, use_math_tricks)
142 }
143 }
144 TreeNode::Op(op, left, right) => {
145 let left_val = apply_algebra_to_tree_node(left, x, tablets, use_math_tricks);
146 let right_val = apply_algebra_to_tree_node(right, x, tablets, use_math_tricks);
147 match op {
148 '+' => left_val + right_val,
149 '-' => left_val - right_val,
150 '*' => left_val * right_val,
151 '/' => left_val / right_val,
152 '^' => {
153 let mut ctx = dec::Context::<Dec>::default();
154 ctx.set_min_exponent(-100).unwrap();
155 ctx.set_max_exponent(100).unwrap();
156 let mut result = left_val;
157 ctx.pow(&mut result, &right_val);
158 result
159 }
160 _ => panic!("Unknown operator: {op}"),
161 }
162 }
163 TreeNode::Paren(expr) => apply_algebra_to_tree_node(expr, x, tablets, use_math_tricks),
164 TreeNode::Empty => Dec::zero(),
165 }
166}
167
168pub fn parse_expression(s: &str) -> TreeNode {
170 let tokens: Vec<char> = s.chars().filter(|c| !c.is_whitespace()).collect();
171 let mut index = 0;
172 parse_additive(&tokens, &mut index)
173}
174
175pub fn create_expression(node: TreeNode) -> String {
177 fn build_expr(node: TreeNode, parent_prec: u8, is_root: bool) -> String {
178 match node {
179 TreeNode::Op(op, left, right) => {
180 let (prec, is_left_assoc) = match op {
181 '^' => (4, false),
182 '*' | '/' => (3, true),
183 '+' | '-' => (2, true),
184 _ => (0, true),
185 };
186 let left_str = build_expr(*left, prec, false);
187 let right_str = build_expr(*right, prec + !is_left_assoc as u8, false);
188 let expr = format!("{left_str}{op}{right_str}");
189 if prec < parent_prec && !is_root {
190 format!("({expr})")
191 } else {
192 expr
193 }
194 }
195 TreeNode::Num(n) => n.to_string(),
196 TreeNode::Var(v) => v,
197 TreeNode::Fun(name, arg) => format!("{}({})", name, build_expr(*arg, 0, false)),
198 TreeNode::Paren(expr) => {
199 let inner = build_expr(*expr, 0, true);
200 if parent_prec > 0 {
201 format!("({inner})")
202 } else {
203 inner
204 }
205 }
206 TreeNode::Empty => String::new(),
207 }
208 }
209 build_expr(node, 0, true)
210}
211
212pub fn level_order_to_array(tree: BinaryAlgebraicExpressionTree) -> [String; 15] {
213 let mut result = std::array::from_fn(|_| String::new());
214 let mut queue = std::collections::VecDeque::with_capacity(15);
215 queue.push_back((0, tree.root_node));
216 while let Some((i, node)) = queue.pop_front() {
217 if i >= 15 {
218 continue;
219 }
220 match node {
221 TreeNode::Op(op, left, right) => {
222 result[i] = op.to_string();
223 queue.push_back((2 * i + 1, *left));
224 queue.push_back((2 * i + 2, *right));
225 }
226 TreeNode::Num(n) => result[i] = n.to_string(),
227 TreeNode::Var(v) => result[i] = v,
228 TreeNode::Fun(name, arg) => {
229 result[i] = name;
230 queue.push_back((2 * i + 2, *arg));
231 }
232 TreeNode::Paren(expr) => {
233 result[i] = "()".to_string();
234 queue.push_back((2 * i + 1, *expr));
235 }
236 TreeNode::Empty => {}
237 }
238 }
239 result
240}
241
242fn trim2(mut dec: Dec) -> String {
243 dec.trim();
244 let result = dec.to_standard_notation_string();
245 if result == "-0" {
246 "0".to_string()
247 } else {
248 result
249 }
250}
251
252fn parse_function(s: &str) -> Option<(&str, &str)> {
253 let parts: Vec<&str> = s.splitn(2, '=').collect();
254 if parts.len() != 2 {
255 return None;
256 }
257 let func_part = parts[0].trim();
258 if !func_part.ends_with(')') || !func_part.contains('(') {
259 return None;
260 }
261 let name = func_part.split('(').next()?;
262 Some((name, parts[1].trim()))
263}
264
265fn parse_function_call(s: &str) -> Option<(&str, &str)> {
266 if !s.ends_with(')') || !s.contains('(') {
267 return None;
268 }
269 let open_paren = s.find('(')?;
270 let name = &s[..open_paren];
271 let input = &s[open_paren + 1..s.len() - 1];
272 Some((name, input))
273}
274
275fn trim_zeros(s: &str) -> String {
276 if s.contains('.') {
277 let trimmed = s.trim_end_matches('0');
278 trimmed.trim_end_matches('.').to_string()
279 } else {
280 s.to_string()
281 }
282}
283
284fn parse_additive(tokens: &[char], index: &mut usize) -> TreeNode {
285 let mut left = parse_multiplicative(tokens, index);
286 while *index < tokens.len() {
287 match tokens[*index] {
288 '+' | '-' => {
289 let op = tokens[*index];
290 *index += 1;
291 let right = parse_multiplicative(tokens, index);
292 left = TreeNode::Op(op, Box::new(left), Box::new(right));
293 }
294 _ => break,
295 }
296 }
297 left
298}
299
300fn parse_multiplicative(tokens: &[char], index: &mut usize) -> TreeNode {
301 let mut left = parse_power(tokens, index);
302 while *index < tokens.len() {
303 match tokens[*index] {
304 '*' | '/' => {
305 let op = tokens[*index];
306 *index += 1;
307 let right = parse_power(tokens, index);
308 left = TreeNode::Op(op, Box::new(left), Box::new(right));
309 }
310 _ => break,
311 }
312 }
313 left
314}
315
316fn parse_power(tokens: &[char], index: &mut usize) -> TreeNode {
317 let mut left = parse_atomic(tokens, index);
318 while *index < tokens.len() && tokens[*index] == '^' {
319 let op = tokens[*index];
320 *index += 1;
321 let right = parse_atomic(tokens, index);
322 left = TreeNode::Op(op, Box::new(left), Box::new(right));
323 }
324 left
325}
326
327fn parse_atomic(tokens: &[char], index: &mut usize) -> TreeNode {
328 if *index >= tokens.len() {
329 return TreeNode::Empty;
330 }
331 let c = tokens[*index];
332 match c {
333 '(' => {
334 *index += 1;
335 let node = parse_additive(tokens, index);
336 if *index < tokens.len() && tokens[*index] == ')' {
337 *index += 1;
338 }
339 TreeNode::Paren(Box::new(node))
340 }
341 '0'..='9' => {
342 let mut num = 0;
343 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
344 num = num * 10 + tokens[*index].to_digit(10).unwrap() as i32;
345 *index += 1;
346 }
347 TreeNode::Num(num)
348 }
349 'x' => {
350 *index += 1;
351 TreeNode::Var("x".to_string())
352 }
353 'A'..='Z' => {
354 let mut name = String::new();
355 while *index < tokens.len()
356 && (tokens[*index].is_alphanumeric() || tokens[*index] == '_')
357 {
358 name.push(tokens[*index]);
359 *index += 1;
360 }
361 if *index < tokens.len() && tokens[*index] == '(' {
362 *index += 1;
363 let arg = parse_additive(tokens, index);
364 if *index < tokens.len() && tokens[*index] == ')' {
365 *index += 1;
366 }
367 TreeNode::Fun(name, Box::new(arg))
368 } else {
369 TreeNode::Var(name)
370 }
371 }
372 _ => TreeNode::Empty,
373 }
374}
375
376pub mod math_trick {
377 use super::*;
378
379 pub fn ge0(x: Dec) -> String {
380 let nan: Dec = NAN.parse().unwrap();
381 match x {
382 _ if x > nan => "1".to_string(),
383 _ if x < nan => "0".to_string(),
384 _ => "NaN".to_string(),
385 }
386 }
387
388 pub fn is0(x: Dec) -> String {
389 let nan: Dec = NAN.parse().unwrap();
390 match x {
391 _ if x < nan => "0".to_string(),
392 _ if x > nan && x < "1".parse::<Dec>().unwrap() + nan => "1".to_string(),
393 _ if x > "1".parse::<Dec>().unwrap() + nan => "0".to_string(),
394 _ => "NaN".to_string(),
395 }
396 }
397
398 pub fn floor1(x: Dec) -> String {
399 let nan: Dec = NAN.parse().unwrap();
400 match x {
401 _ if x < nan => "0".to_string(),
402 _ if x > nan && x < "1".parse::<Dec>().unwrap() + nan => "0".to_string(),
403 _ if x > "1".parse::<Dec>().unwrap() + nan && x < "2".parse::<Dec>().unwrap() + nan => {
404 "1".to_string()
405 }
406 _ if x > "2".parse::<Dec>().unwrap() + nan && x < "3".parse::<Dec>().unwrap() + nan => {
407 "2".to_string()
408 }
409 _ if x > "3".parse::<Dec>().unwrap() + nan && x < "4".parse::<Dec>().unwrap() + nan => {
410 "3".to_string()
411 }
412 _ if x > "4".parse::<Dec>().unwrap() + nan && x < "5".parse::<Dec>().unwrap() + nan => {
413 "4".to_string()
414 }
415 _ if x > "5".parse::<Dec>().unwrap() + nan && x < "6".parse::<Dec>().unwrap() + nan => {
416 "5".to_string()
417 }
418 _ if x > "6".parse::<Dec>().unwrap() + nan && x < "7".parse::<Dec>().unwrap() + nan => {
419 "6".to_string()
420 }
421 _ if x > "7".parse::<Dec>().unwrap() + nan && x < "8".parse::<Dec>().unwrap() + nan => {
422 "7".to_string()
423 }
424 _ if x > "8".parse::<Dec>().unwrap() + nan && x < "9".parse::<Dec>().unwrap() + nan => {
425 "8".to_string()
426 }
427 _ if x > "9".parse::<Dec>().unwrap() + nan
428 && x < "10".parse::<Dec>().unwrap() + nan =>
429 {
430 "9".to_string()
431 }
432 _ if x > "10".parse::<Dec>().unwrap() + nan => "0".to_string(),
433 _ => "NaN".to_string(),
434 }
435 }
436
437 pub fn left(mut num: String) -> String {
439 if floor1(num.parse::<Dec>().unwrap() * "10".parse::<Dec>().unwrap()) == "NaN" {
441 return "NaN".to_string();
442 }
443 if !num.contains('.') {
444 num += ".0";
445 }
446 if num.ends_with('0') {
447 num = num.trim_end_matches('0').to_string()
448 }
449 if num.ends_with('.') {
450 num += "0";
451 }
452 let decimal_pos = num.find('.').unwrap();
453 let (integer_part, fractional_part) = num.split_at(decimal_pos + 1);
454 let mut chars: Vec<_> = fractional_part.chars().collect();
455 let len = DECIMAL_PLACES_DEFAULT - chars.len();
456 if len > 0 {
457 chars.extend(vec!['0'; len]);
458 }
459 chars.rotate_right(1);
460 let rotated_fractional_part: String = chars.into_iter().collect();
461 let result = format!("{integer_part}{rotated_fractional_part}");
462 trim_zeros(&result)
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469
470 fn get_test_cases() -> &'static Vec<TestCase> {
471 static INSTANCE: std::sync::OnceLock<Vec<TestCase>> = std::sync::OnceLock::new();
472 INSTANCE.get_or_init(|| {
473 vec![
474 TestCase {
475 description: None,
476 examples: vec![
477 ["2".to_string(), "27".to_string()],
478 ["-0.2424".to_string(), "27".to_string()],
479 ["100".to_string(), "27".to_string()],
480 ],
481 solution: vec![BinaryAlgebraicExpressionTree {
482 name: "DECIMAL_PLACES".to_string(),
483 root_node: parse_expression("27")
484 }],
485 },
486 TestCase {
487 description: None,
488 examples: vec![
489 ["-1".to_string(), "1".to_string()],
490 ["11.9".to_string(), "11.9".to_string()],
491 ["0".to_string(), "0".to_string()],
492 ["-0.0024".to_string(), "0.0024".to_string()],
493 ["1".to_string(), "1".to_string()],
494 ],
495 solution: vec![BinaryAlgebraicExpressionTree {
496 name: "ABS".to_string(),
497 root_node: parse_expression("(x^2)^(1/2)")
498 }],
499 },
500 TestCase {
501 description: None,
502 examples: vec![
503 ["0".to_string(), "NaN".to_string()],
504 ["0.3".to_string(), "1".to_string()],
505 ["-0.3".to_string(), "0".to_string()],
506 ["1.0".to_string(), "1".to_string()],
507 ["400.0".to_string(), "1".to_string()],
508 ],
509 solution: vec![BinaryAlgebraicExpressionTree {
510 name: "H".to_string(),
511 root_node: parse_expression("(x+ABS(x))/(2*x)")
512 }],
513 },
514 TestCase {
515 description: None,
516 examples: vec![
517 [
518 "55".to_string(),
519 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "1",
520 ],
521 [
522 "-11.9".to_string(),
523 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "1",
524 ],
525 [
526 "0.0".to_string(),
527 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "1",
528 ],
529 [
530 "-0.95".to_string(),
531 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "1",
532 ],
533 ],
534 solution: vec![BinaryAlgebraicExpressionTree {
535 name: "TINY".to_string(),
536 root_node: parse_expression("10^(-DECIMAL_PLACES(x)))")
537 }],
538 },
539 TestCase {
540 description: None,
541 examples: vec![
542 [
543 "0.".to_string() + &"9".repeat(DECIMAL_PLACES_DEFAULT),
544 "1".to_string(),
545 ],
546 [
547 "-0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT) + "1",
548 "NaN".to_string(),
549 ],
550 ["0.3".to_string(), "1".to_string()],
551 ["-0.3".to_string(), "0".to_string()],
552 ["1.0".to_string(), "1".to_string()],
553 ["400.0".to_string(), "1".to_string()],
554 ],
555 solution: vec![BinaryAlgebraicExpressionTree {
556 name: "GE0".to_string(),
557 root_node: parse_expression("H(x+TINY(x)/10)")
558 }],
559 },
560 TestCase {
561 description: None,
562 examples: vec![
563 ["0".to_string(), "1".to_string()],
564 ["-6.4".to_string(), "1".to_string()],
565 ["1.0".to_string(), "0".to_string()],
566 ["0.999".to_string(), "1".to_string()],
567 ["50".to_string(), "0".to_string()],
568 ],
569 solution: vec![BinaryAlgebraicExpressionTree {
570 name: "LT1".to_string(),
571 root_node: parse_expression("1-GE0(x-1)")
572 }],
573 },
574 TestCase {
575 description: None,
576 examples: vec![
577 ["0".to_string(), "1".to_string()],
578 ["0.5".to_string(), "1".to_string()],
579 ["1".to_string(), "0".to_string()],
580 ],
581 solution: vec![BinaryAlgebraicExpressionTree {
582 name: "IS0".to_string(),
583 root_node: parse_expression("GE0(x)*LT1(x)")
584 }],
585 },
586 TestCase {
587 description: None,
588 examples: vec![
589 ["1".to_string(), "1".to_string()],
590 ["1.5".to_string(), "1".to_string()],
591 ["2".to_string(), "0".to_string()],
592 ],
593 solution: vec![BinaryAlgebraicExpressionTree {
594 name: "IS1".to_string(),
595 root_node: parse_expression("IS0(x-1)")
596 }],
597 },
598 TestCase {
599 description: None,
600 examples: vec![
601 ["2".to_string(), "1".to_string()],
602 ["2.5".to_string(), "1".to_string()],
603 ["3".to_string(), "0".to_string()],
604 ],
605 solution: vec![BinaryAlgebraicExpressionTree {
606 name: "IS2".to_string(),
607 root_node: parse_expression("IS0(x-2)")
608 }],
609 },
610 TestCase {
611 description: None,
612 examples: vec![
613 ["3".to_string(), "1".to_string()],
614 ["3.5".to_string(), "1".to_string()],
615 ["4".to_string(), "0".to_string()],
616 ],
617 solution: vec![BinaryAlgebraicExpressionTree {
618 name: "IS3".to_string(),
619 root_node: parse_expression("IS0(x-3)")
620 }],
621 },
622 TestCase {
623 description: None,
624 examples: vec![
625 ["4".to_string(), "1".to_string()],
626 ["4.5".to_string(), "1".to_string()],
627 ["5".to_string(), "0".to_string()],
628 ],
629 solution: vec![BinaryAlgebraicExpressionTree {
630 name: "IS4".to_string(),
631 root_node: parse_expression("IS0(x-4)")
632 }],
633 },
634 TestCase {
635 description: None,
636 examples: vec![
637 ["5".to_string(), "1".to_string()],
638 ["5.5".to_string(), "1".to_string()],
639 ["6".to_string(), "0".to_string()],
640 ],
641 solution: vec![BinaryAlgebraicExpressionTree {
642 name: "IS5".to_string(),
643 root_node: parse_expression("IS0(x-5)")
644 }],
645 },
646 TestCase {
647 description: None,
648 examples: vec![
649 ["6".to_string(), "1".to_string()],
650 ["6.5".to_string(), "1".to_string()],
651 ["7".to_string(), "0".to_string()],
652 ],
653 solution: vec![BinaryAlgebraicExpressionTree {
654 name: "IS6".to_string(),
655 root_node: parse_expression("IS0(x-6)"),
656 }],
657 },
658 TestCase {
659 description: None,
660 examples: vec![
661 ["7".to_string(), "1".to_string()],
662 ["7.5".to_string(), "1".to_string()],
663 ["8".to_string(), "0".to_string()],
664 ],
665 solution: vec![BinaryAlgebraicExpressionTree {
666 name: "IS7".to_string(),
667 root_node: parse_expression("IS0(x-7)"),
668 }],
669 },
670 TestCase {
671 description: None,
672 examples: vec![
673 ["8".to_string(), "1".to_string()],
674 ["8.5".to_string(), "1".to_string()],
675 ["9".to_string(), "0".to_string()],
676 ],
677 solution: vec![BinaryAlgebraicExpressionTree {
678 name: "IS8".to_string(),
679 root_node: parse_expression("IS0(x-8)"),
680 }],
681 },
682 TestCase {
683 description: None,
684 examples: vec![
685 ["9".to_string(), "1".to_string()],
686 ["9.5".to_string(), "1".to_string()],
687 ["10".to_string(), "0".to_string()],
688 ],
689 solution: vec![BinaryAlgebraicExpressionTree {
690 name: "IS9".to_string(),
691 root_node: parse_expression("IS0(x-9)"),
692 }],
693 },
694 TestCase {
695 description: None,
696 examples: vec![
697 ["0".to_string(), "0".to_string()],
698 ["0.2".to_string(), "0".to_string()],
699 ["1".to_string(), "1".to_string()],
700 ["1.2".to_string(), "1".to_string()],
701 ["2".to_string(), "2".to_string()],
702 ["2.2".to_string(), "2".to_string()],
703 ["3".to_string(), "3".to_string()],
704 ["3.2".to_string(), "3".to_string()],
705 ["4".to_string(), "4".to_string()],
706 ["4.2".to_string(), "4".to_string()],
707 ["5".to_string(), "5".to_string()],
708 ["5.2".to_string(), "5".to_string()],
709 ["6".to_string(), "6".to_string()],
710 ["6.2".to_string(), "6".to_string()],
711 ["7".to_string(), "7".to_string()],
712 ["7.2".to_string(), "7".to_string()],
713 ["8".to_string(), "8".to_string()],
714 ["8.2".to_string(), "8".to_string()],
715 ["9".to_string(), "9".to_string()],
716 ["9.2".to_string(), "9".to_string()],
717 ],
718 solution: vec![BinaryAlgebraicExpressionTree {
719 name: "FLOOR1".to_string(),
720 root_node: parse_expression(
721 "IS1(x)+2*IS2(x)+3*IS3(x)+4*IS4(x)+5*IS5(x)+6*IS6(x)+7*IS7(x)+8*IS8(x)+9*IS9(x)",
722 ),
723 }],
724 },
725 TestCase {
726 description: None,
727 examples: vec![
728 ["0.06".to_string(), "0.6".to_string()],
729 [
730 "0.12345678".to_string(),
731 "0.2345678".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 8) + "1",
732 ],
733 [
734 "0.7".to_string(),
735 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "7",
736 ],
737 ],
738 solution: vec![
739 BinaryAlgebraicExpressionTree {
740 name: "RIGHT".to_string(),
741 root_node: parse_expression("x*10-FLOOR1(x*10)+FLOOR1(x*10)*TINY(x)")
742 },
743 ],
744 },
745 TestCase {
746 description: None,
747 examples: vec![
748 ["0.6".to_string(), "0.06".to_string()],
749 [
750 "0.2345678".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 8) + "1",
751 "0.12345678".to_string(),
752 ],
753 [
754 "0.".to_string() + &"0".repeat(DECIMAL_PLACES_DEFAULT - 1) + "7",
755 "0.7".to_string(),
756 ],
757 ],
758 solution: vec![
759 BinaryAlgebraicExpressionTree {
760 name: "LEFT".to_string(),
761 root_node: parse_expression(
762 "RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(RIGHT(x))))))))))))))))))))))))))",
763 )
764 },
765 ],
766 },
767 ]
768 })
769 }
770
771 #[test]
772 fn test_solutions() {
773 let tasks = get_test_cases();
774 let mut trees: Vec<BinaryAlgebraicExpressionTree> = vec![];
775 for task in tasks {
776 for tree in &task.solution {
777 trees.push(tree.clone());
778 }
779 }
780 for i in 0..tasks.len() {
781 for [input, output] in &tasks[i].examples {
782 let name_function = &tasks[i].solution.last().unwrap().name;
783 let name = format!("{}({}) = ", name_function, input);
784 let result = trim2(apply_algebra_to_tree_node(
785 &tasks[i].solution.last().unwrap().root_node,
786 &input.parse::<Dec>().unwrap(),
787 &trees,
788 true,
789 ));
790 assert_eq!(name.clone() + output.as_str(), name + &result);
791 }
792 }
793 }
794
795 #[test]
796 fn test_math_tricks() {
797 let tasks = get_test_cases();
798 let mut trees: Vec<BinaryAlgebraicExpressionTree> = vec![];
799 for task in tasks {
800 for tree in &task.solution {
801 trees.push(tree.clone());
802 }
803 }
804 for i in 0..tasks.len() {
805 for [input, output] in &tasks[i].examples {
806 let name_function = &tasks[i].solution.last().unwrap().name;
807 let name = format!("{}({}) = ", name_function, input);
808 let input_dec = input.parse().unwrap();
809 if name_function == "GE0" {
810 assert_eq!(
811 name.clone() + output.as_str(),
812 name + &math_trick::ge0(input_dec)
813 );
814 } else if name_function == "IS0" {
815 assert_eq!(
816 name.clone() + output.as_str(),
817 name + &math_trick::is0(input_dec)
818 );
819 } else if name_function == "FLOOR1" {
820 assert_eq!(
821 name.clone() + output.as_str(),
822 name + &math_trick::floor1(input_dec)
823 );
824 } else if name_function == "LEFT" {
825 assert_eq!(
826 name.clone() + output.as_str(),
827 name + &math_trick::left(input_dec.to_standard_notation_string())
828 );
829 }
830 }
831 }
832 }
833}