1use serde::{Deserialize, Serialize};
2use std::io::{self, Read};
3use std::sync::OnceLock;
4
5mod decimal_crate;
6use decimal_crate::*;
7
8static DECIMAL_PLACES: OnceLock<usize> = OnceLock::new();
9static NAN: OnceLock<String> = OnceLock::new();
10
11#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
12pub enum TreeNode {
13 Op(char, Box<TreeNode>, Box<TreeNode>),
14 Num(String),
15 Var(String),
16 Fun(String, usize, Box<TreeNode>),
17 Paren(Box<TreeNode>),
18 Empty,
19}
20
21#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
23pub struct BinaryAlgebraicExpressionTree {
24 pub name: String,
25 pub root_node: TreeNode,
26}
27
28#[derive(Clone, Debug, Serialize, Deserialize)]
30pub struct TestCase {
31 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
46fn get_decimal_places() -> usize {
47 *DECIMAL_PLACES.get_or_init(|| MAX_DECIMAL_PLACES)
48}
49
50fn get_nan() -> &'static String {
51 NAN.get_or_init(|| format!("-0.{}1", "0".repeat(get_decimal_places())))
52}
53
54#[cfg(not(target_arch = "wasm32"))]
55fn output(s: String) {
56 println!("{s}");
57}
58
59#[cfg(target_arch = "wasm32")]
60fn output(s: String) {
61 use web_sys::wasm_bindgen::JsCast;
62 let window = web_sys::window().unwrap();
63 let document = window.document().unwrap();
64 let textarea = document
65 .get_element_by_id("output")
66 .unwrap()
67 .dyn_into::<web_sys::HtmlTextAreaElement>()
68 .unwrap();
69 textarea.set_value(&s);
70}
71
72#[cfg(not(target_arch = "wasm32"))]
73fn read_args() -> Vec<String> {
74 std::env::args().skip(1).collect()
75}
76
77#[cfg(target_arch = "wasm32")]
78fn read_args() -> Vec<String> {
79 use web_sys::wasm_bindgen::JsCast;
80 let window = web_sys::window().unwrap();
81 let document = window.document().unwrap();
82 vec![
83 document
84 .get_element_by_id("sva")
85 .unwrap()
86 .dyn_into::<web_sys::HtmlTextAreaElement>()
87 .unwrap()
88 .value(),
89 ]
90}
91
92pub fn read_input() {
94 let mut use_math_tricks = false;
95 let args: Vec<String> = read_args();
96 if args.len() == 1
97 && let Some(first_line) = args[0].trim().lines().next()
98 && first_line.trim().starts_with("decimals(x) =")
99 {
100 use_math_tricks = true;
101 if let Some(k_str) = first_line.trim().strip_prefix("decimals(x) =") {
102 let k_clean = k_str.split_whitespace().next().unwrap_or(k_str);
103 if let Ok(k) = k_clean.parse::<usize>() {
104 let _ = DECIMAL_PLACES.set(k);
105 let _ = NAN.set(format!("-0.{}1", "0".repeat(k)));
106 }
107 }
108 }
109 let input = if args.len() == 1 && args[0].contains('\n') {
110 args[0]
111 .split('\n')
112 .map(|s| s.trim())
113 .filter(|s| !s.is_empty())
114 .map(|s| s.to_string())
115 .collect()
116 } else if args.is_empty() {
117 let mut buffer = String::new();
118 io::stdin().read_to_string(&mut buffer).unwrap();
119 buffer
120 .split('\n')
121 .map(|s| s.trim())
122 .filter(|s| !s.is_empty())
123 .map(|s| s.to_string())
124 .collect()
125 } else {
126 args
127 };
128 if input.is_empty() {
129 println!(
130 "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"
131 );
132 return;
133 }
134 let mut trees = Vec::new();
135 for arg in input.iter().take(input.len() - 1) {
136 if let Some((name, expr)) = parse_function(arg) {
137 let tree = BinaryAlgebraicExpressionTree {
138 name: name.to_string(),
139 root_node: parse_expression(expr),
140 };
141 trees.push(tree);
142 } else {
143 output(format!("Invalid function definition: {arg}"));
144 return;
145 }
146 }
147 if let Some((func_name, input_val)) = parse_function_call(input.last().unwrap()) {
148 if let Some(tree) = trees.iter().find(|t| t.name == func_name) {
149 let x: Dec = input_val.parse().unwrap_or_else(|_| {
150 output(format!("Invalid input value: {input_val}"));
151 std::process::exit(1);
152 });
153 let result = apply_algebra_to_tree_node(&tree.root_node, &x, &trees, use_math_tricks);
154 output(result.map_or("Undefined".to_string(), trim2));
155 } else {
156 output(format!("Function {func_name} not defined"));
157 }
158 } else {
159 output(format!("Invalid function call: {}", input.last().unwrap()));
160 }
161}
162
163pub fn apply_algebra_to_tree_node(
165 node: &TreeNode,
166 x: &Dec,
167 tablets: &Vec<BinaryAlgebraicExpressionTree>,
168 use_math_tricks: bool,
169) -> Option<Dec> {
170 match node {
171 TreeNode::Num(n) => Some(n.parse::<Dec>().unwrap()),
172 TreeNode::Var(s) => {
173 if s == "x" {
174 Some(x.clone())
175 } else {
176 Some(
177 s.parse::<Dec>()
178 .unwrap_or_else(|_| panic!("Unexpected variable: {s}")),
179 )
180 }
181 }
182 TreeNode::Fun(name, iterate, arg) => {
183 let mut arg_value = apply_algebra_to_tree_node(arg, x, tablets, use_math_tricks);
184 let mut old_value = arg_value.clone();
185 for _ in 0..*iterate {
186 if name.as_str() == "abs" && use_math_tricks {
187 arg_value = Some(math_trick::abs(arg_value.unwrap()).parse().unwrap());
188 } else if name.as_str() == "ge0" && use_math_tricks {
189 arg_value = Some(math_trick::ge0(arg_value.unwrap()).parse().unwrap());
190 } else if name.as_str() == "is0" && use_math_tricks {
191 arg_value = Some(math_trick::is0(arg_value.unwrap()).parse().unwrap());
192 } else if name.as_str() == "floor1" && use_math_tricks {
193 arg_value = Some(math_trick::floor1(arg_value.unwrap()).parse().unwrap());
194 } else if name.as_str() == "left" && use_math_tricks {
195 arg_value = Some(math_trick::left(arg_value.unwrap()).parse().unwrap());
196 } else {
197 let tablet = tablets
198 .iter()
199 .find(|tablet| name == &tablet.name)
200 .unwrap_or_else(|| panic!("There is no tree called {name}"));
201 arg_value = apply_algebra_to_tree_node(
202 &tablet.root_node,
203 &arg_value.unwrap(),
204 tablets,
205 use_math_tricks,
206 );
207 }
208 if arg_value == old_value {
209 break;
210 }
211 old_value = arg_value.clone();
212 }
213 arg_value
214 }
215 TreeNode::Op(op, left, right) => {
216 let left_val = apply_algebra_to_tree_node(left, x, tablets, use_math_tricks);
217 let right_val = apply_algebra_to_tree_node(right, x, tablets, use_math_tricks);
218 let left_str = trim2(left_val.clone().unwrap());
219 let right_str = trim2(right_val.clone().unwrap());
220 match op {
221 '+' => Some(left_val.unwrap() + right_val.unwrap()),
222 '-' => Some(left_val.unwrap() - right_val.unwrap()),
223 '*' => Some(left_val.unwrap() * right_val.unwrap()),
224 '/' => {
225 if right_str == "0" {
226 return None;
227 }
228 Some(left_val.unwrap() / right_val.unwrap())
229 }
230 '^' => {
231 if (left_str == "0" && (right_val <= Some(zero())))
232 || (left_val < Some(zero()) && right_str.contains('.'))
233 {
234 return None;
235 }
236 Some(pow(left_val.unwrap(), right_val.unwrap()))
237 }
238 _ => panic!("Unknown operator: {op}"),
239 }
240 }
241 TreeNode::Paren(expr) => apply_algebra_to_tree_node(expr, x, tablets, use_math_tricks),
242 TreeNode::Empty => Some(zero()),
243 }
244}
245
246pub fn parse_expression(s: &str) -> TreeNode {
248 let tokens: Vec<char> = s.chars().filter(|c| !c.is_whitespace()).collect();
249 let mut index = 0;
250 parse_additive(&tokens, &mut index)
251}
252
253pub fn create_expression(node: TreeNode) -> String {
255 fn build_expr(node: TreeNode, parent_prec: u8, is_root: bool) -> String {
256 match node {
257 TreeNode::Op(op, left, right) => {
258 let (prec, is_left_assoc) = match op {
259 '^' => (4, false),
260 '*' | '/' => (3, true),
261 '+' | '-' => (2, true),
262 _ => (0, true),
263 };
264 let left_str = build_expr(*left, prec, false);
265 let right_str = build_expr(*right, prec + !is_left_assoc as u8, false);
266 let expr = format!("{left_str}{op}{right_str}");
267 if prec < parent_prec && !is_root {
268 format!("({expr})")
269 } else {
270 expr
271 }
272 }
273 TreeNode::Num(n) => n.to_string(),
274 TreeNode::Var(v) => v,
275 TreeNode::Fun(name, iterate, arg) => {
276 let mut iterating = "".to_string();
277 if iterate > 1 {
278 iterating = "^[".to_string() + &iterate.to_string() + "]";
279 }
280 format!("{}{}({})", name, iterating, build_expr(*arg, 0, false))
281 }
282 TreeNode::Paren(expr) => {
283 let inner = build_expr(*expr, 0, true);
284 if parent_prec > 0 {
285 format!("({inner})")
286 } else {
287 inner
288 }
289 }
290 TreeNode::Empty => String::new(),
291 }
292 }
293 build_expr(node, 0, true)
294}
295
296pub fn level_order_to_array(root: TreeNode) -> [String; 15] {
297 let mut result = std::array::from_fn(|_| String::new());
298 let mut queue = std::collections::VecDeque::with_capacity(15);
299 queue.push_back((0, root));
300 while let Some((i, node)) = queue.pop_front() {
301 if i >= 15 {
302 continue;
303 }
304 match node {
305 TreeNode::Paren(expr) => {
306 queue.push_front((i, *expr));
307 }
308 TreeNode::Op(op, left, right) => {
309 result[i] = op.to_string();
310 queue.push_back((2 * i + 1, *left));
311 queue.push_back((2 * i + 2, *right));
312 }
313 TreeNode::Num(n) => result[i] = n.to_string(),
314 TreeNode::Var(v) => result[i] = v,
315 TreeNode::Fun(name, _iterate, arg) => {
316 result[i] = name;
317 queue.push_back((2 * i + 2, *arg));
318 }
319 TreeNode::Empty => {}
320 }
321 }
322 result
323}
324
325pub fn trim2(dec: Dec) -> String {
326 let mut x = dec_to_string(dec);
327 if x.contains('.') {
328 x = x.trim_end_matches('0').trim_end_matches('.').to_string();
329 }
330 if x.starts_with("-0") {
331 x.remove(0);
332 }
333 x
334}
335
336fn parse_function(s: &str) -> Option<(&str, &str)> {
337 let s = s.trim();
338 if let Some((func_part, expr)) = s.split_once('=') {
339 let func_part = func_part.trim();
340 if let Some((name, _)) = func_part.split_once('(') {
341 return Some((name, expr.trim()));
342 }
343 }
344 None
345}
346
347fn parse_function_call(s: &str) -> Option<(&str, &str)> {
348 if !s.ends_with(')') || !s.contains('(') {
349 return None;
350 }
351 let open_paren = s.find('(')?;
352 let name = &s[..open_paren];
353 let input = &s[open_paren + 1..s.len() - 1];
354 Some((name, input))
355}
356
357fn trim_zeros(s: &str) -> String {
358 if s.contains('.') {
359 let trimmed = s.trim_end_matches('0');
360 trimmed.trim_end_matches('.').to_string()
361 } else {
362 s.to_string()
363 }
364}
365
366fn parse_additive(tokens: &[char], index: &mut usize) -> TreeNode {
367 let mut left = parse_multiplicative(tokens, index);
368 while *index < tokens.len() {
369 match tokens[*index] {
370 '+' | '-' => {
371 let op = tokens[*index];
372 *index += 1;
373 let right = parse_multiplicative(tokens, index);
374 left = TreeNode::Op(op, Box::new(left), Box::new(right));
375 }
376 _ => break,
377 }
378 }
379 left
380}
381
382fn parse_multiplicative(tokens: &[char], index: &mut usize) -> TreeNode {
383 let mut left = parse_power(tokens, index);
384 while *index < tokens.len() {
385 match tokens[*index] {
386 '*' | '/' => {
387 let op = tokens[*index];
388 *index += 1;
389 let right = parse_power(tokens, index);
390 left = TreeNode::Op(op, Box::new(left), Box::new(right));
391 }
392 _ => break,
393 }
394 }
395 left
396}
397
398fn parse_atomic(tokens: &[char], index: &mut usize) -> TreeNode {
399 if *index >= tokens.len() {
400 return TreeNode::Empty;
401 }
402 let c = tokens[*index];
403
404 match c {
405 '(' => {
406 *index += 1;
407 let node = parse_additive(tokens, index);
408 if *index < tokens.len() && tokens[*index] == ')' {
409 *index += 1;
410 }
411 TreeNode::Paren(Box::new(node))
412 }
413 '0'..='9' => {
414 let mut num_str = String::new();
415 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
416 num_str.push(tokens[*index]);
417 *index += 1;
418 }
419 if *index < tokens.len() && tokens[*index] == '.' {
420 num_str.push(tokens[*index]);
421 *index += 1;
422 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
423 num_str.push(tokens[*index]);
424 *index += 1;
425 }
426 }
427 TreeNode::Num(num_str)
428 }
429 'A'..='Z' | 'a'..='z' => {
430 let mut name = String::new();
431 let mut iterate: usize = 1;
432 while *index < tokens.len()
433 && (tokens[*index].is_alphanumeric() || tokens[*index] == '_')
434 {
435 name.push(tokens[*index]);
436 *index += 1;
437 }
438 if *index < tokens.len() && tokens[*index] == '^' {
439 let saved_index = *index;
440 *index += 1;
441 if *index < tokens.len() && tokens[*index] == '[' {
442 *index += 1;
443 let mut num_str = String::new();
444 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
445 num_str.push(tokens[*index]);
446 *index += 1;
447 }
448 if *index < tokens.len() && tokens[*index] == ']' {
449 *index += 1;
450 if let Ok(parsed_iterate) = num_str.parse::<usize>() {
451 iterate = parsed_iterate;
452 }
453 } else {
454 *index = saved_index;
455 }
456 } else {
457 *index = saved_index;
458 }
459 }
460
461 if *index < tokens.len() && tokens[*index] == '(' {
462 *index += 1;
463 let arg = parse_additive(tokens, index);
464 if *index < tokens.len() && tokens[*index] == ')' {
465 *index += 1;
466 }
467 TreeNode::Fun(name, iterate, Box::new(arg))
468 } else if name == "x" {
469 TreeNode::Var("x".to_string())
470 } else {
471 TreeNode::Empty
472 }
473 }
474 _ => {
475 *index += 1;
476 TreeNode::Empty
477 }
478 }
479}
480
481fn parse_unary(tokens: &[char], index: &mut usize) -> TreeNode {
482 if *index >= tokens.len() {
483 return TreeNode::Empty;
484 }
485
486 match tokens[*index] {
488 '+' => {
489 *index += 1;
490 parse_unary(tokens, index) }
492 '-' => {
493 *index += 1;
494 if *index < tokens.len() && (tokens[*index].is_ascii_digit() || tokens[*index] == '.') {
496 let mut num_str = String::from("-");
498 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
499 num_str.push(tokens[*index]);
500 *index += 1;
501 }
502 if *index < tokens.len() && tokens[*index] == '.' {
503 num_str.push(tokens[*index]);
504 *index += 1;
505 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
506 num_str.push(tokens[*index]);
507 *index += 1;
508 }
509 }
510 TreeNode::Num(num_str)
511 } else {
512 TreeNode::Op(
514 '-',
515 Box::new(TreeNode::Num("0".to_string())),
516 Box::new(parse_unary(tokens, index)),
517 )
518 }
519 }
520 _ => parse_atomic(tokens, index),
521 }
522}
523
524fn parse_power(tokens: &[char], index: &mut usize) -> TreeNode {
526 let mut left = parse_unary(tokens, index);
527 while *index < tokens.len() && tokens[*index] == '^' {
528 let op = tokens[*index];
529 *index += 1;
530 let right = parse_unary(tokens, index);
531 left = TreeNode::Op(op, Box::new(left), Box::new(right));
532 }
533 left
534}
535
536pub mod math_trick {
537 use super::*;
538
539 pub fn abs(x: Dec) -> String {
540 let mut res = x.to_string();
541 if res.starts_with('-') {
542 res.remove(0);
543 }
544 res
545 }
546
547 pub fn ge0(x: Dec) -> String {
548 let nan: Dec = get_nan().parse().unwrap();
549 match x {
550 _ if x > nan => "1".to_string(),
551 _ if x < nan => "0".to_string(),
552 _ => "NaN".to_string(),
553 }
554 }
555
556 pub fn is0(x: Dec) -> String {
557 let nan: Dec = get_nan().parse().unwrap();
558 match x {
559 _ if x < nan => "0".to_string(),
560 _ if x > nan && x < "1".parse::<Dec>().unwrap() + &nan => "1".to_string(),
561 _ if x > "1".parse::<Dec>().unwrap() + nan => "0".to_string(),
562 _ => "NaN".to_string(),
563 }
564 }
565
566 pub fn floor1(x: Dec) -> String {
567 let nan: Dec = get_nan().parse().unwrap();
568 match x {
569 _ if x < nan => "0".to_string(),
570 _ if x > nan && x < "1".parse::<Dec>().unwrap() + &nan => "0".to_string(),
571 _ if x > "1".parse::<Dec>().unwrap() + &nan
572 && x < "2".parse::<Dec>().unwrap() + &nan =>
573 {
574 "1".to_string()
575 }
576 _ if x > "2".parse::<Dec>().unwrap() + &nan
577 && x < "3".parse::<Dec>().unwrap() + &nan =>
578 {
579 "2".to_string()
580 }
581 _ if x > "3".parse::<Dec>().unwrap() + &nan
582 && x < "4".parse::<Dec>().unwrap() + &nan =>
583 {
584 "3".to_string()
585 }
586 _ if x > "4".parse::<Dec>().unwrap() + &nan
587 && x < "5".parse::<Dec>().unwrap() + &nan =>
588 {
589 "4".to_string()
590 }
591 _ if x > "5".parse::<Dec>().unwrap() + &nan
592 && x < "6".parse::<Dec>().unwrap() + &nan =>
593 {
594 "5".to_string()
595 }
596 _ if x > "6".parse::<Dec>().unwrap() + &nan
597 && x < "7".parse::<Dec>().unwrap() + &nan =>
598 {
599 "6".to_string()
600 }
601 _ if x > "7".parse::<Dec>().unwrap() + &nan
602 && x < "8".parse::<Dec>().unwrap() + &nan =>
603 {
604 "7".to_string()
605 }
606 _ if x > "8".parse::<Dec>().unwrap() + &nan
607 && x < "9".parse::<Dec>().unwrap() + &nan =>
608 {
609 "8".to_string()
610 }
611 _ if x > "9".parse::<Dec>().unwrap() + &nan
612 && x < "10".parse::<Dec>().unwrap() + &nan =>
613 {
614 "9".to_string()
615 }
616 _ if x > "10".parse::<Dec>().unwrap() + &nan => "0".to_string(),
617 _ => "NaN".to_string(),
618 }
619 }
620
621 pub fn left(x: Dec) -> String {
623 let mut num = dec_to_string(x);
625 if floor1(num.parse::<Dec>().unwrap() * "10".parse::<Dec>().unwrap()) == "NaN" {
626 return "NaN".to_string();
627 }
628 if !num.contains('.') {
629 num += ".0";
630 }
631 if num.ends_with('0') {
632 num = num.trim_end_matches('0').to_string()
633 }
634 if num.ends_with('.') {
635 num += "0";
636 }
637 let decimal_pos = num.find('.').unwrap();
638 let (integer_part, fractional_part) = num.split_at(decimal_pos + 1);
639 let mut chars: Vec<_> = fractional_part.chars().collect();
640 let len = get_decimal_places() - chars.len();
641 if len > 0 {
642 chars.extend(vec!['0'; len]);
643 }
644 chars.rotate_right(1);
645 let rotated_fractional_part: String = chars.into_iter().collect();
646 let result = format!("{integer_part}{rotated_fractional_part}");
647 trim_zeros(&result)
648 }
649}
650
651#[cfg(test)]
652mod tests {
653 use super::*;
654
655 fn get_test_cases() -> &'static Vec<TestCase> {
656 static INSTANCE: std::sync::OnceLock<Vec<TestCase>> = std::sync::OnceLock::new();
657 INSTANCE.get_or_init(|| {
658 vec![
659 TestCase {
660 description: None,
661 examples: vec![
662 ["2".to_string(), get_decimal_places().to_string()],
663 ["-0.2424".to_string(), get_decimal_places().to_string()],
664 ["100".to_string(), get_decimal_places().to_string()],
665 ],
666 solution: vec![BinaryAlgebraicExpressionTree {
667 name: "decimal_places".to_string(),
668 root_node: parse_expression(&get_decimal_places().to_string())
669 }],
670 },
671 TestCase {
672 description: None,
673 examples: vec![
674 ["-1".to_string(), "1".to_string()],
675 ["11.2".to_string(), "11.2".to_string()],
676 ["0".to_string(), "0".to_string()],
677 ["-0.0025".to_string(), "0.0025".to_string()],
678 ["1".to_string(), "1".to_string()],
679 ],
680 solution: vec![BinaryAlgebraicExpressionTree {
681 name: "abs".to_string(),
682 root_node: parse_expression("(x^2)^0.5")
683 }],
684 },
685 TestCase {
686 description: None,
687 examples: vec![
688 ["0.3".to_string(), "1".to_string()],
690 ["-0.3".to_string(), "0".to_string()],
691 ["1.0".to_string(), "1".to_string()],
692 ["400.0".to_string(), "1".to_string()],
693 ],
694 solution: vec![BinaryAlgebraicExpressionTree {
695 name: "H".to_string(),
696 root_node: parse_expression("(x+abs(x))/(2*x)")
697 }],
698 },
699 TestCase {
700 description: None,
701 examples: vec![
702 [
703 "55".to_string(),
704 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
705 ],
706 [
707 "-11.9".to_string(),
708 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
709 ],
710 [
711 "0.0".to_string(),
712 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
713 ],
714 [
715 "-0.95".to_string(),
716 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
717 ],
718 ],
719 solution: vec![BinaryAlgebraicExpressionTree {
720 name: "tiny".to_string(),
721 root_node: parse_expression("10^(-decimal_places(x)))")
722 }],
723 },
724 TestCase {
725 description: None,
726 examples: vec![
727 [
728 "0.".to_string() + &"9".repeat(get_decimal_places()),
729 "1".to_string(),
730 ],
731 ["0.3".to_string(), "1".to_string()],
736 ["-0.3".to_string(), "0".to_string()],
737 ["1.0".to_string(), "1".to_string()],
738 ["400.0".to_string(), "1".to_string()],
739 ],
740 solution: vec![BinaryAlgebraicExpressionTree {
741 name: "ge0".to_string(),
742 root_node: parse_expression("H(x+tiny(x)/10)")
743 }],
744 },
745 TestCase {
746 description: None,
747 examples: vec![
748 ["0".to_string(), "1".to_string()],
749 ["-6.4".to_string(), "1".to_string()],
750 ["1.0".to_string(), "0".to_string()],
751 ["0.999".to_string(), "1".to_string()],
752 ["50".to_string(), "0".to_string()],
753 ],
754 solution: vec![BinaryAlgebraicExpressionTree {
755 name: "lt1".to_string(),
756 root_node: parse_expression("1-ge0(x-1)")
757 }],
758 },
759 TestCase {
760 description: None,
761 examples: vec![
762 ["0".to_string(), "1".to_string()],
763 ["0.5".to_string(), "1".to_string()],
764 ["1".to_string(), "0".to_string()],
765 ],
766 solution: vec![BinaryAlgebraicExpressionTree {
767 name: "is0".to_string(),
768 root_node: parse_expression("ge0(x)*lt1(x)")
769 }],
770 },
771 TestCase {
772 description: None,
773 examples: vec![
774 ["1".to_string(), "1".to_string()],
775 ["1.5".to_string(), "1".to_string()],
776 ["2".to_string(), "0".to_string()],
777 ],
778 solution: vec![BinaryAlgebraicExpressionTree {
779 name: "is1".to_string(),
780 root_node: parse_expression("is0(x-1)")
781 }],
782 },
783 TestCase {
784 description: None,
785 examples: vec![
786 ["2".to_string(), "1".to_string()],
787 ["2.5".to_string(), "1".to_string()],
788 ["3".to_string(), "0".to_string()],
789 ],
790 solution: vec![BinaryAlgebraicExpressionTree {
791 name: "is2".to_string(),
792 root_node: parse_expression("is0(x-2)")
793 }],
794 },
795 TestCase {
796 description: None,
797 examples: vec![
798 ["3".to_string(), "1".to_string()],
799 ["3.5".to_string(), "1".to_string()],
800 ["4".to_string(), "0".to_string()],
801 ],
802 solution: vec![BinaryAlgebraicExpressionTree {
803 name: "is3".to_string(),
804 root_node: parse_expression("is0(x-3)")
805 }],
806 },
807 TestCase {
808 description: None,
809 examples: vec![
810 ["4".to_string(), "1".to_string()],
811 ["4.5".to_string(), "1".to_string()],
812 ["5".to_string(), "0".to_string()],
813 ],
814 solution: vec![BinaryAlgebraicExpressionTree {
815 name: "is4".to_string(),
816 root_node: parse_expression("is0(x-4)")
817 }],
818 },
819 TestCase {
820 description: None,
821 examples: vec![
822 ["5".to_string(), "1".to_string()],
823 ["5.5".to_string(), "1".to_string()],
824 ["6".to_string(), "0".to_string()],
825 ],
826 solution: vec![BinaryAlgebraicExpressionTree {
827 name: "is5".to_string(),
828 root_node: parse_expression("is0(x-5)")
829 }],
830 },
831 TestCase {
832 description: None,
833 examples: vec![
834 ["6".to_string(), "1".to_string()],
835 ["6.5".to_string(), "1".to_string()],
836 ["7".to_string(), "0".to_string()],
837 ],
838 solution: vec![BinaryAlgebraicExpressionTree {
839 name: "is6".to_string(),
840 root_node: parse_expression("is0(x-6)"),
841 }],
842 },
843 TestCase {
844 description: None,
845 examples: vec![
846 ["7".to_string(), "1".to_string()],
847 ["7.5".to_string(), "1".to_string()],
848 ["8".to_string(), "0".to_string()],
849 ],
850 solution: vec![BinaryAlgebraicExpressionTree {
851 name: "is7".to_string(),
852 root_node: parse_expression("is0(x-7)"),
853 }],
854 },
855 TestCase {
856 description: None,
857 examples: vec![
858 ["8".to_string(), "1".to_string()],
859 ["8.5".to_string(), "1".to_string()],
860 ["9".to_string(), "0".to_string()],
861 ],
862 solution: vec![BinaryAlgebraicExpressionTree {
863 name: "is8".to_string(),
864 root_node: parse_expression("is0(x-8)"),
865 }],
866 },
867 TestCase {
868 description: None,
869 examples: vec![
870 ["9".to_string(), "1".to_string()],
871 ["9.5".to_string(), "1".to_string()],
872 ["10".to_string(), "0".to_string()],
873 ],
874 solution: vec![BinaryAlgebraicExpressionTree {
875 name: "is9".to_string(),
876 root_node: parse_expression("is0(x-9)"),
877 }],
878 },
879 TestCase {
880 description: None,
881 examples: vec![
882 ["0".to_string(), "0".to_string()],
883 ["0.2".to_string(), "0".to_string()],
884 ["1".to_string(), "1".to_string()],
885 ["1.2".to_string(), "1".to_string()],
886 ["2".to_string(), "2".to_string()],
887 ["2.2".to_string(), "2".to_string()],
888 ["3".to_string(), "3".to_string()],
889 ["3.2".to_string(), "3".to_string()],
890 ["4".to_string(), "4".to_string()],
891 ["4.2".to_string(), "4".to_string()],
892 ["5".to_string(), "5".to_string()],
893 ["5.2".to_string(), "5".to_string()],
894 ["6".to_string(), "6".to_string()],
895 ["6.2".to_string(), "6".to_string()],
896 ["7".to_string(), "7".to_string()],
897 ["7.2".to_string(), "7".to_string()],
898 ["8".to_string(), "8".to_string()],
899 ["8.2".to_string(), "8".to_string()],
900 ["9".to_string(), "9".to_string()],
901 ["9.2".to_string(), "9".to_string()],
902 ],
903 solution: vec![BinaryAlgebraicExpressionTree {
904 name: "floor1".to_string(),
905 root_node: parse_expression(
906 "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)",
907 ),
908 }],
909 },
910 TestCase {
911 description: None,
912 examples: vec![
913 ["0.06".to_string(), "0.6".to_string()],
914 [
915 "0.12345678".to_string(),
916 "0.2345678".to_string() + &"0".repeat(get_decimal_places() - 8) + "1",
917 ],
918 [
919 "0.7".to_string(),
920 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "7",
921 ],
922 ],
923 solution: vec![
924 BinaryAlgebraicExpressionTree {
925 name: "right".to_string(),
926 root_node: parse_expression("x*10-floor1(x*10)+floor1(x*10)*tiny(x)")
927 },
928 ],
929 },
930 TestCase {
931 description: None,
932 examples: vec![
933 [
934 "0.2345678".to_string() + &"0".repeat(get_decimal_places() - 8) + "1",
935 "0.12345678".to_string(),
936 ],
937 [
938 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "7",
939 "0.7".to_string(),
940 ],
941 ],
942 solution: vec![
943 BinaryAlgebraicExpressionTree {
944 name: "left".to_string(),
945 root_node: parse_expression(
946 &("right(".repeat(get_decimal_places() - 1) + "(x)" + &")".repeat(get_decimal_places() - 1))
947 )
948 },
949 ],
950 },
951 ]
952 })
953 }
954
955 #[test]
956 fn test_solutions() {
957 let tasks = get_test_cases();
958 let trees: Vec<BinaryAlgebraicExpressionTree> = tasks
959 .iter()
960 .flat_map(|task| &task.solution)
961 .cloned()
962 .collect();
963 for i in 0..tasks.len() {
964 for [input, output] in &tasks[i].examples {
965 let name_function = &tasks[i].solution.last().unwrap().name;
966 let result = trim2(
967 apply_algebra_to_tree_node(
968 &tasks[i].solution.last().unwrap().root_node,
969 &input.parse::<Dec>().unwrap(),
970 &trees,
971 true,
972 )
973 .unwrap(),
974 );
975 assert_eq!(
976 format!("{}({}) = {}", name_function, input, output),
977 format!("{}({}) = {}", name_function, input, result)
978 );
979 }
980 }
981 }
982
983 #[test]
984 fn test_math_tricks() {
985 let tasks = get_test_cases();
986 let mut trees: Vec<BinaryAlgebraicExpressionTree> = vec![];
987 for task in tasks {
988 for tree in &task.solution {
989 trees.push(tree.clone());
990 }
991 }
992 for i in 0..tasks.len() {
993 for [input, output] in &tasks[i].examples {
994 let name_function = &tasks[i].solution.last().unwrap().name;
995 let input_dec = input.parse().unwrap();
996 let result = match name_function.as_str() {
997 "abs" => math_trick::abs(input_dec),
998 "ge0" => math_trick::ge0(input_dec),
999 "is0" => math_trick::is0(input_dec),
1000 "floor1" => math_trick::floor1(input_dec),
1001 "left" => math_trick::left(input_dec),
1002 _ => continue,
1003 };
1004 assert_eq!(
1005 format!("{}({}) = {}", name_function, input, output),
1006 format!("{}({}) = {}", name_function, input, result)
1007 );
1008 }
1009 }
1010 }
1011}