1use crate::error::{AlgorithmError, Result};
12use oxigdal_core::buffer::RasterBuffer;
13
14#[cfg(not(feature = "std"))]
15use alloc::{string::String, vec::Vec};
16
17#[cfg(feature = "parallel")]
18use rayon::prelude::*;
19
20#[derive(Debug, Clone, PartialEq)]
22enum Token {
23 Number(f64),
25 Band(usize),
27 Ident(String),
29 Plus,
31 Minus,
32 Multiply,
33 Divide,
34 Power,
35 LeftParen,
37 RightParen,
38 Greater,
40 Less,
41 GreaterEqual,
42 LessEqual,
43 Equal,
44 NotEqual,
45 And,
47 Or,
48 If,
50 Then,
51 Else,
52 Comma,
54}
55
56#[derive(Debug, Clone)]
58enum Expr {
59 Number(f64),
61 Band(usize),
63 BinaryOp {
65 left: Box<Expr>,
66 op: BinaryOp,
67 right: Box<Expr>,
68 },
69 UnaryOp { op: UnaryOp, expr: Box<Expr> },
71 Function { name: String, args: Vec<Expr> },
73 Conditional {
75 condition: Box<Expr>,
76 then_expr: Box<Expr>,
77 else_expr: Box<Expr>,
78 },
79}
80
81#[derive(Debug, Clone, Copy, PartialEq)]
83enum BinaryOp {
84 Add,
85 Subtract,
86 Multiply,
87 Divide,
88 Power,
89 Greater,
90 Less,
91 GreaterEqual,
92 LessEqual,
93 Equal,
94 NotEqual,
95 And,
96 Or,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq)]
101enum UnaryOp {
102 Negate,
103}
104
105struct Lexer {
107 input: Vec<char>,
108 pos: usize,
109}
110
111impl Lexer {
112 fn new(input: &str) -> Self {
113 Self {
114 input: input.chars().collect(),
115 pos: 0,
116 }
117 }
118
119 fn current(&self) -> Option<char> {
120 if self.pos < self.input.len() {
121 Some(self.input[self.pos])
122 } else {
123 None
124 }
125 }
126
127 fn advance(&mut self) {
128 self.pos += 1;
129 }
130
131 fn skip_whitespace(&mut self) {
132 while let Some(c) = self.current() {
133 if c.is_whitespace() {
134 self.advance();
135 } else {
136 break;
137 }
138 }
139 }
140
141 fn read_number(&mut self) -> Result<f64> {
142 let mut num_str = String::new();
143 let mut has_dot = false;
144
145 while let Some(c) = self.current() {
146 if c.is_ascii_digit() {
147 num_str.push(c);
148 self.advance();
149 } else if c == '.' && !has_dot {
150 has_dot = true;
151 num_str.push(c);
152 self.advance();
153 } else {
154 break;
155 }
156 }
157
158 num_str
159 .parse::<f64>()
160 .map_err(|_| AlgorithmError::InvalidParameter {
161 parameter: "expression",
162 message: format!("Invalid number: {num_str}"),
163 })
164 }
165
166 fn read_ident(&mut self) -> String {
167 let mut ident = String::new();
168
169 while let Some(c) = self.current() {
170 if c.is_alphanumeric() || c == '_' {
171 ident.push(c);
172 self.advance();
173 } else {
174 break;
175 }
176 }
177
178 ident
179 }
180
181 fn next_token(&mut self) -> Result<Option<Token>> {
182 self.skip_whitespace();
183
184 let c = match self.current() {
185 Some(c) => c,
186 None => return Ok(None),
187 };
188
189 let token = if c.is_ascii_digit() {
190 Token::Number(self.read_number()?)
191 } else if c.is_alphabetic() || c == 'B' {
192 let ident = self.read_ident();
193
194 if ident.starts_with('B') && ident.len() > 1 {
196 let band_num = ident[1..].parse::<usize>().ok();
197 if let Some(num) = band_num {
198 return Ok(Some(Token::Band(num)));
199 }
200 }
201
202 match ident.as_str() {
204 "if" | "IF" => Token::If,
205 "then" | "THEN" => Token::Then,
206 "else" | "ELSE" => Token::Else,
207 "and" | "AND" => Token::And,
208 "or" | "OR" => Token::Or,
209 _ => Token::Ident(ident),
210 }
211 } else {
212 self.advance();
213 match c {
214 '+' => Token::Plus,
215 '-' => Token::Minus,
216 '*' => Token::Multiply,
217 '/' => Token::Divide,
218 '^' => Token::Power,
219 '(' => Token::LeftParen,
220 ')' => Token::RightParen,
221 ',' => Token::Comma,
222 '>' => {
223 if self.current() == Some('=') {
224 self.advance();
225 Token::GreaterEqual
226 } else {
227 Token::Greater
228 }
229 }
230 '<' => {
231 if self.current() == Some('=') {
232 self.advance();
233 Token::LessEqual
234 } else {
235 Token::Less
236 }
237 }
238 '=' => {
239 if self.current() == Some('=') {
240 self.advance();
241 Token::Equal
242 } else {
243 return Err(AlgorithmError::InvalidParameter {
244 parameter: "expression",
245 message: "Expected '==' for equality comparison".to_string(),
246 });
247 }
248 }
249 '!' => {
250 if self.current() == Some('=') {
251 self.advance();
252 Token::NotEqual
253 } else {
254 return Err(AlgorithmError::InvalidParameter {
255 parameter: "expression",
256 message: "Expected '!=' for inequality comparison".to_string(),
257 });
258 }
259 }
260 _ => {
261 return Err(AlgorithmError::InvalidParameter {
262 parameter: "expression",
263 message: format!("Unexpected character: {c}"),
264 });
265 }
266 }
267 };
268
269 Ok(Some(token))
270 }
271
272 fn tokenize(&mut self) -> Result<Vec<Token>> {
273 let mut tokens = Vec::new();
274
275 while let Some(token) = self.next_token()? {
276 tokens.push(token);
277 }
278
279 Ok(tokens)
280 }
281}
282
283struct Parser {
285 tokens: Vec<Token>,
286 pos: usize,
287}
288
289impl Parser {
290 fn new(tokens: Vec<Token>) -> Self {
291 Self { tokens, pos: 0 }
292 }
293
294 fn current(&self) -> Option<&Token> {
295 self.tokens.get(self.pos)
296 }
297
298 fn advance(&mut self) {
299 self.pos += 1;
300 }
301
302 fn parse(&mut self) -> Result<Expr> {
303 self.parse_conditional()
304 }
305
306 fn parse_conditional(&mut self) -> Result<Expr> {
307 if matches!(self.current(), Some(Token::If)) {
308 self.advance();
309 let condition = Box::new(self.parse_or()?);
310
311 if !matches!(self.current(), Some(Token::Then)) {
312 return Err(AlgorithmError::InvalidParameter {
313 parameter: "expression",
314 message: "Expected 'then' after if condition".to_string(),
315 });
316 }
317 self.advance();
318
319 let then_expr = Box::new(self.parse_or()?);
320
321 if !matches!(self.current(), Some(Token::Else)) {
322 return Err(AlgorithmError::InvalidParameter {
323 parameter: "expression",
324 message: "Expected 'else' in conditional".to_string(),
325 });
326 }
327 self.advance();
328
329 let else_expr = Box::new(self.parse_or()?);
330
331 Ok(Expr::Conditional {
332 condition,
333 then_expr,
334 else_expr,
335 })
336 } else {
337 self.parse_or()
338 }
339 }
340
341 fn parse_or(&mut self) -> Result<Expr> {
342 let mut left = self.parse_and()?;
343
344 while matches!(self.current(), Some(Token::Or)) {
345 self.advance();
346 let right = self.parse_and()?;
347 left = Expr::BinaryOp {
348 left: Box::new(left),
349 op: BinaryOp::Or,
350 right: Box::new(right),
351 };
352 }
353
354 Ok(left)
355 }
356
357 fn parse_and(&mut self) -> Result<Expr> {
358 let mut left = self.parse_comparison()?;
359
360 while matches!(self.current(), Some(Token::And)) {
361 self.advance();
362 let right = self.parse_comparison()?;
363 left = Expr::BinaryOp {
364 left: Box::new(left),
365 op: BinaryOp::And,
366 right: Box::new(right),
367 };
368 }
369
370 Ok(left)
371 }
372
373 fn parse_comparison(&mut self) -> Result<Expr> {
374 let mut left = self.parse_additive()?;
375
376 while let Some(token) = self.current() {
377 let op = match token {
378 Token::Greater => BinaryOp::Greater,
379 Token::Less => BinaryOp::Less,
380 Token::GreaterEqual => BinaryOp::GreaterEqual,
381 Token::LessEqual => BinaryOp::LessEqual,
382 Token::Equal => BinaryOp::Equal,
383 Token::NotEqual => BinaryOp::NotEqual,
384 _ => break,
385 };
386
387 self.advance();
388 let right = self.parse_additive()?;
389 left = Expr::BinaryOp {
390 left: Box::new(left),
391 op,
392 right: Box::new(right),
393 };
394 }
395
396 Ok(left)
397 }
398
399 fn parse_additive(&mut self) -> Result<Expr> {
400 let mut left = self.parse_multiplicative()?;
401
402 while let Some(token) = self.current() {
403 let op = match token {
404 Token::Plus => BinaryOp::Add,
405 Token::Minus => BinaryOp::Subtract,
406 _ => break,
407 };
408
409 self.advance();
410 let right = self.parse_multiplicative()?;
411 left = Expr::BinaryOp {
412 left: Box::new(left),
413 op,
414 right: Box::new(right),
415 };
416 }
417
418 Ok(left)
419 }
420
421 fn parse_multiplicative(&mut self) -> Result<Expr> {
422 let mut left = self.parse_power()?;
423
424 while let Some(token) = self.current() {
425 let op = match token {
426 Token::Multiply => BinaryOp::Multiply,
427 Token::Divide => BinaryOp::Divide,
428 _ => break,
429 };
430
431 self.advance();
432 let right = self.parse_power()?;
433 left = Expr::BinaryOp {
434 left: Box::new(left),
435 op,
436 right: Box::new(right),
437 };
438 }
439
440 Ok(left)
441 }
442
443 fn parse_power(&mut self) -> Result<Expr> {
444 let mut left = self.parse_unary()?;
445
446 while matches!(self.current(), Some(Token::Power)) {
447 self.advance();
448 let right = self.parse_unary()?;
449 left = Expr::BinaryOp {
450 left: Box::new(left),
451 op: BinaryOp::Power,
452 right: Box::new(right),
453 };
454 }
455
456 Ok(left)
457 }
458
459 fn parse_unary(&mut self) -> Result<Expr> {
460 if matches!(self.current(), Some(Token::Minus)) {
461 self.advance();
462 let expr = self.parse_unary()?;
463 Ok(Expr::UnaryOp {
464 op: UnaryOp::Negate,
465 expr: Box::new(expr),
466 })
467 } else {
468 self.parse_primary()
469 }
470 }
471
472 fn parse_primary(&mut self) -> Result<Expr> {
473 match self.current() {
474 Some(Token::Number(n)) => {
475 let val = *n;
476 self.advance();
477 Ok(Expr::Number(val))
478 }
479 Some(Token::Band(b)) => {
480 let band = *b;
481 self.advance();
482 Ok(Expr::Band(band))
483 }
484 Some(Token::Ident(name)) => {
485 let func_name = name.clone();
486 self.advance();
487
488 if matches!(self.current(), Some(Token::LeftParen)) {
489 self.advance();
490 let mut args = Vec::new();
491
492 if !matches!(self.current(), Some(Token::RightParen)) {
493 loop {
494 args.push(self.parse_conditional()?);
495
496 if matches!(self.current(), Some(Token::Comma)) {
497 self.advance();
498 } else {
499 break;
500 }
501 }
502 }
503
504 if !matches!(self.current(), Some(Token::RightParen)) {
505 return Err(AlgorithmError::InvalidParameter {
506 parameter: "expression",
507 message: "Expected ')' after function arguments".to_string(),
508 });
509 }
510 self.advance();
511
512 Ok(Expr::Function {
513 name: func_name,
514 args,
515 })
516 } else {
517 Err(AlgorithmError::InvalidParameter {
518 parameter: "expression",
519 message: format!("Unknown identifier: {func_name}"),
520 })
521 }
522 }
523 Some(Token::LeftParen) => {
524 self.advance();
525 let expr = self.parse_conditional()?;
526
527 if !matches!(self.current(), Some(Token::RightParen)) {
528 return Err(AlgorithmError::InvalidParameter {
529 parameter: "expression",
530 message: "Expected ')'".to_string(),
531 });
532 }
533 self.advance();
534
535 Ok(expr)
536 }
537 _ => Err(AlgorithmError::InvalidParameter {
538 parameter: "expression",
539 message: "Unexpected token in expression".to_string(),
540 }),
541 }
542 }
543}
544
545struct Optimizer;
547
548impl Optimizer {
549 fn optimize(expr: Expr) -> Expr {
551 let expr = Self::constant_fold(expr);
552 let expr = Self::algebraic_simplify(expr);
553 Self::eliminate_common_subexpressions(expr)
554 }
555
556 fn constant_fold(expr: Expr) -> Expr {
558 match expr {
559 Expr::BinaryOp { left, op, right } => {
560 let left = Self::constant_fold(*left);
561 let right = Self::constant_fold(*right);
562
563 if let (Expr::Number(l), Expr::Number(r)) = (&left, &right) {
565 let result = match op {
566 BinaryOp::Add => l + r,
567 BinaryOp::Subtract => l - r,
568 BinaryOp::Multiply => l * r,
569 BinaryOp::Divide => {
570 if r.abs() < f64::EPSILON {
571 f64::NAN
572 } else {
573 l / r
574 }
575 }
576 BinaryOp::Power => l.powf(*r),
577 BinaryOp::Greater => {
578 if l > r {
579 1.0
580 } else {
581 0.0
582 }
583 }
584 BinaryOp::Less => {
585 if l < r {
586 1.0
587 } else {
588 0.0
589 }
590 }
591 BinaryOp::GreaterEqual => {
592 if l >= r {
593 1.0
594 } else {
595 0.0
596 }
597 }
598 BinaryOp::LessEqual => {
599 if l <= r {
600 1.0
601 } else {
602 0.0
603 }
604 }
605 BinaryOp::Equal => {
606 if (l - r).abs() < f64::EPSILON {
607 1.0
608 } else {
609 0.0
610 }
611 }
612 BinaryOp::NotEqual => {
613 if (l - r).abs() >= f64::EPSILON {
614 1.0
615 } else {
616 0.0
617 }
618 }
619 BinaryOp::And => {
620 if *l != 0.0 && *r != 0.0 {
621 1.0
622 } else {
623 0.0
624 }
625 }
626 BinaryOp::Or => {
627 if *l != 0.0 || *r != 0.0 {
628 1.0
629 } else {
630 0.0
631 }
632 }
633 };
634 return Expr::Number(result);
635 }
636
637 Expr::BinaryOp {
638 left: Box::new(left),
639 op,
640 right: Box::new(right),
641 }
642 }
643 Expr::UnaryOp { op, expr } => {
644 let expr = Self::constant_fold(*expr);
645 if let Expr::Number(n) = expr {
646 let result = match op {
647 UnaryOp::Negate => -n,
648 };
649 return Expr::Number(result);
650 }
651 Expr::UnaryOp {
652 op,
653 expr: Box::new(expr),
654 }
655 }
656 Expr::Function { name, args } => {
657 let args: Vec<Expr> = args.into_iter().map(Self::constant_fold).collect();
658
659 let all_const = args.iter().all(|arg| matches!(arg, Expr::Number(_)));
661 if all_const {
662 let arg_vals: Vec<f64> = args
663 .iter()
664 .filter_map(|arg| {
665 if let Expr::Number(n) = arg {
666 Some(*n)
667 } else {
668 None
669 }
670 })
671 .collect();
672
673 let result = match name.as_str() {
674 "sqrt" if arg_vals.len() == 1 => Some(arg_vals[0].sqrt()),
675 "abs" if arg_vals.len() == 1 => Some(arg_vals[0].abs()),
676 "log" if arg_vals.len() == 1 => Some(arg_vals[0].ln()),
677 "log10" if arg_vals.len() == 1 => Some(arg_vals[0].log10()),
678 "exp" if arg_vals.len() == 1 => Some(arg_vals[0].exp()),
679 "sin" if arg_vals.len() == 1 => Some(arg_vals[0].sin()),
680 "cos" if arg_vals.len() == 1 => Some(arg_vals[0].cos()),
681 "tan" if arg_vals.len() == 1 => Some(arg_vals[0].tan()),
682 "floor" if arg_vals.len() == 1 => Some(arg_vals[0].floor()),
683 "ceil" if arg_vals.len() == 1 => Some(arg_vals[0].ceil()),
684 "round" if arg_vals.len() == 1 => Some(arg_vals[0].round()),
685 "min" if !arg_vals.is_empty() => {
686 Some(arg_vals.iter().copied().fold(f64::INFINITY, f64::min))
687 }
688 "max" if !arg_vals.is_empty() => {
689 Some(arg_vals.iter().copied().fold(f64::NEG_INFINITY, f64::max))
690 }
691 _ => None,
692 };
693
694 if let Some(val) = result {
695 return Expr::Number(val);
696 }
697 }
698
699 Expr::Function { name, args }
700 }
701 Expr::Conditional {
702 condition,
703 then_expr,
704 else_expr,
705 } => {
706 let condition = Self::constant_fold(*condition);
707 let then_expr = Self::constant_fold(*then_expr);
708 let else_expr = Self::constant_fold(*else_expr);
709
710 if let Expr::Number(cond) = condition {
712 if cond != 0.0 {
713 return then_expr;
714 } else {
715 return else_expr;
716 }
717 }
718
719 Expr::Conditional {
720 condition: Box::new(condition),
721 then_expr: Box::new(then_expr),
722 else_expr: Box::new(else_expr),
723 }
724 }
725 other => other,
726 }
727 }
728
729 fn algebraic_simplify(expr: Expr) -> Expr {
731 match expr {
732 Expr::BinaryOp { left, op, right } => {
733 let left = Self::algebraic_simplify(*left);
734 let right = Self::algebraic_simplify(*right);
735
736 match (&left, op, &right) {
737 (_, BinaryOp::Add, Expr::Number(n)) if n.abs() < f64::EPSILON => left,
739 (Expr::Number(n), BinaryOp::Add, _) if n.abs() < f64::EPSILON => right,
740
741 (_, BinaryOp::Subtract, Expr::Number(n)) if n.abs() < f64::EPSILON => left,
743
744 (_, BinaryOp::Multiply, Expr::Number(n))
746 | (Expr::Number(n), BinaryOp::Multiply, _)
747 if n.abs() < f64::EPSILON =>
748 {
749 Expr::Number(0.0)
750 }
751
752 (_, BinaryOp::Multiply, Expr::Number(n)) if (n - 1.0).abs() < f64::EPSILON => {
754 left
755 }
756 (Expr::Number(n), BinaryOp::Multiply, _) if (n - 1.0).abs() < f64::EPSILON => {
757 right
758 }
759
760 (_, BinaryOp::Divide, Expr::Number(n)) if (n - 1.0).abs() < f64::EPSILON => {
762 left
763 }
764
765 (_, BinaryOp::Power, Expr::Number(n)) if n.abs() < f64::EPSILON => {
767 Expr::Number(1.0)
768 }
769
770 (_, BinaryOp::Power, Expr::Number(n)) if (n - 1.0).abs() < f64::EPSILON => left,
772
773 _ => Expr::BinaryOp {
774 left: Box::new(left),
775 op,
776 right: Box::new(right),
777 },
778 }
779 }
780 Expr::UnaryOp { op, expr } => {
781 let expr = Self::algebraic_simplify(*expr);
782 Expr::UnaryOp {
783 op,
784 expr: Box::new(expr),
785 }
786 }
787 Expr::Function { name, args } => {
788 let args = args.into_iter().map(Self::algebraic_simplify).collect();
789 Expr::Function { name, args }
790 }
791 Expr::Conditional {
792 condition,
793 then_expr,
794 else_expr,
795 } => Expr::Conditional {
796 condition: Box::new(Self::algebraic_simplify(*condition)),
797 then_expr: Box::new(Self::algebraic_simplify(*then_expr)),
798 else_expr: Box::new(Self::algebraic_simplify(*else_expr)),
799 },
800 other => other,
801 }
802 }
803
804 fn eliminate_common_subexpressions(expr: Expr) -> Expr {
807 expr
813 }
814}
815
816struct Evaluator<'a> {
818 bands: &'a [RasterBuffer],
819}
820
821impl<'a> Evaluator<'a> {
822 fn new(bands: &'a [RasterBuffer]) -> Self {
823 Self { bands }
824 }
825
826 fn eval_pixel(&self, expr: &Expr, x: u64, y: u64) -> Result<f64> {
827 match expr {
828 Expr::Number(n) => Ok(*n),
829 Expr::Band(b) => {
830 if *b == 0 || *b > self.bands.len() {
831 return Err(AlgorithmError::InvalidParameter {
832 parameter: "band",
833 message: format!("Band {} out of range (1-{})", b, self.bands.len()),
834 });
835 }
836 self.bands[b - 1]
837 .get_pixel(x, y)
838 .map_err(AlgorithmError::Core)
839 }
840 Expr::BinaryOp { left, op, right } => {
841 let lval = self.eval_pixel(left, x, y)?;
842 let rval = self.eval_pixel(right, x, y)?;
843
844 let result = match op {
845 BinaryOp::Add => lval + rval,
846 BinaryOp::Subtract => lval - rval,
847 BinaryOp::Multiply => lval * rval,
848 BinaryOp::Divide => {
849 if rval.abs() < f64::EPSILON {
850 f64::NAN
851 } else {
852 lval / rval
853 }
854 }
855 BinaryOp::Power => lval.powf(rval),
856 BinaryOp::Greater => {
857 if lval > rval {
858 1.0
859 } else {
860 0.0
861 }
862 }
863 BinaryOp::Less => {
864 if lval < rval {
865 1.0
866 } else {
867 0.0
868 }
869 }
870 BinaryOp::GreaterEqual => {
871 if lval >= rval {
872 1.0
873 } else {
874 0.0
875 }
876 }
877 BinaryOp::LessEqual => {
878 if lval <= rval {
879 1.0
880 } else {
881 0.0
882 }
883 }
884 BinaryOp::Equal => {
885 if (lval - rval).abs() < f64::EPSILON {
886 1.0
887 } else {
888 0.0
889 }
890 }
891 BinaryOp::NotEqual => {
892 if (lval - rval).abs() >= f64::EPSILON {
893 1.0
894 } else {
895 0.0
896 }
897 }
898 BinaryOp::And => {
899 if lval != 0.0 && rval != 0.0 {
900 1.0
901 } else {
902 0.0
903 }
904 }
905 BinaryOp::Or => {
906 if lval != 0.0 || rval != 0.0 {
907 1.0
908 } else {
909 0.0
910 }
911 }
912 };
913
914 Ok(result)
915 }
916 Expr::UnaryOp { op, expr } => {
917 let val = self.eval_pixel(expr, x, y)?;
918 match op {
919 UnaryOp::Negate => Ok(-val),
920 }
921 }
922 Expr::Function { name, args } => self.eval_function(name, args, x, y),
923 Expr::Conditional {
924 condition,
925 then_expr,
926 else_expr,
927 } => {
928 let cond_val = self.eval_pixel(condition, x, y)?;
929 if cond_val != 0.0 {
930 self.eval_pixel(then_expr, x, y)
931 } else {
932 self.eval_pixel(else_expr, x, y)
933 }
934 }
935 }
936 }
937
938 fn eval_function(&self, name: &str, args: &[Expr], x: u64, y: u64) -> Result<f64> {
939 let arg_vals: Result<Vec<f64>> =
940 args.iter().map(|arg| self.eval_pixel(arg, x, y)).collect();
941 let arg_vals = arg_vals?;
942
943 let result = match name {
944 "sqrt" => {
945 if arg_vals.len() != 1 {
946 return Err(AlgorithmError::InvalidParameter {
947 parameter: "sqrt",
948 message: "Expected 1 argument".to_string(),
949 });
950 }
951 arg_vals[0].sqrt()
952 }
953 "abs" => {
954 if arg_vals.len() != 1 {
955 return Err(AlgorithmError::InvalidParameter {
956 parameter: "abs",
957 message: "Expected 1 argument".to_string(),
958 });
959 }
960 arg_vals[0].abs()
961 }
962 "log" => {
963 if arg_vals.len() != 1 {
964 return Err(AlgorithmError::InvalidParameter {
965 parameter: "log",
966 message: "Expected 1 argument".to_string(),
967 });
968 }
969 arg_vals[0].ln()
970 }
971 "log10" => {
972 if arg_vals.len() != 1 {
973 return Err(AlgorithmError::InvalidParameter {
974 parameter: "log10",
975 message: "Expected 1 argument".to_string(),
976 });
977 }
978 arg_vals[0].log10()
979 }
980 "exp" => {
981 if arg_vals.len() != 1 {
982 return Err(AlgorithmError::InvalidParameter {
983 parameter: "exp",
984 message: "Expected 1 argument".to_string(),
985 });
986 }
987 arg_vals[0].exp()
988 }
989 "sin" => {
990 if arg_vals.len() != 1 {
991 return Err(AlgorithmError::InvalidParameter {
992 parameter: "sin",
993 message: "Expected 1 argument".to_string(),
994 });
995 }
996 arg_vals[0].sin()
997 }
998 "cos" => {
999 if arg_vals.len() != 1 {
1000 return Err(AlgorithmError::InvalidParameter {
1001 parameter: "cos",
1002 message: "Expected 1 argument".to_string(),
1003 });
1004 }
1005 arg_vals[0].cos()
1006 }
1007 "tan" => {
1008 if arg_vals.len() != 1 {
1009 return Err(AlgorithmError::InvalidParameter {
1010 parameter: "tan",
1011 message: "Expected 1 argument".to_string(),
1012 });
1013 }
1014 arg_vals[0].tan()
1015 }
1016 "floor" => {
1017 if arg_vals.len() != 1 {
1018 return Err(AlgorithmError::InvalidParameter {
1019 parameter: "floor",
1020 message: "Expected 1 argument".to_string(),
1021 });
1022 }
1023 arg_vals[0].floor()
1024 }
1025 "ceil" => {
1026 if arg_vals.len() != 1 {
1027 return Err(AlgorithmError::InvalidParameter {
1028 parameter: "ceil",
1029 message: "Expected 1 argument".to_string(),
1030 });
1031 }
1032 arg_vals[0].ceil()
1033 }
1034 "round" => {
1035 if arg_vals.len() != 1 {
1036 return Err(AlgorithmError::InvalidParameter {
1037 parameter: "round",
1038 message: "Expected 1 argument".to_string(),
1039 });
1040 }
1041 arg_vals[0].round()
1042 }
1043 "min" => {
1044 if arg_vals.is_empty() {
1045 return Err(AlgorithmError::InvalidParameter {
1046 parameter: "min",
1047 message: "Expected at least 1 argument".to_string(),
1048 });
1049 }
1050 arg_vals.iter().copied().fold(f64::INFINITY, f64::min)
1051 }
1052 "max" => {
1053 if arg_vals.is_empty() {
1054 return Err(AlgorithmError::InvalidParameter {
1055 parameter: "max",
1056 message: "Expected at least 1 argument".to_string(),
1057 });
1058 }
1059 arg_vals.iter().copied().fold(f64::NEG_INFINITY, f64::max)
1060 }
1061 _ => {
1062 return Err(AlgorithmError::InvalidParameter {
1063 parameter: "function",
1064 message: format!("Unknown function: {name}"),
1065 });
1066 }
1067 };
1068
1069 Ok(result)
1070 }
1071}
1072
1073pub struct RasterCalculator;
1075
1076impl RasterCalculator {
1077 pub fn evaluate(expression: &str, bands: &[RasterBuffer]) -> Result<RasterBuffer> {
1094 if bands.is_empty() {
1095 return Err(AlgorithmError::EmptyInput {
1096 operation: "evaluate",
1097 });
1098 }
1099
1100 let width = bands[0].width();
1102 let height = bands[0].height();
1103 for (_i, band) in bands.iter().enumerate().skip(1) {
1104 if band.width() != width || band.height() != height {
1105 return Err(AlgorithmError::InvalidDimensions {
1106 message: "All bands must have same dimensions",
1107 actual: band.width() as usize,
1108 expected: width as usize,
1109 });
1110 }
1111 }
1112
1113 let mut lexer = Lexer::new(expression);
1115 let tokens = lexer.tokenize()?;
1116
1117 let mut parser = Parser::new(tokens);
1119 let expr = parser.parse()?;
1120
1121 let expr = Optimizer::optimize(expr);
1123
1124 let evaluator = Evaluator::new(bands);
1126 let mut result = RasterBuffer::zeros(width, height, bands[0].data_type());
1127
1128 for y in 0..height {
1129 for x in 0..width {
1130 let value = evaluator.eval_pixel(&expr, x, y)?;
1131 result
1132 .set_pixel(x, y, value)
1133 .map_err(AlgorithmError::Core)?;
1134 }
1135 }
1136
1137 Ok(result)
1138 }
1139
1140 #[cfg(feature = "parallel")]
1160 pub fn evaluate_parallel(expression: &str, bands: &[RasterBuffer]) -> Result<RasterBuffer> {
1161 if bands.is_empty() {
1162 return Err(AlgorithmError::EmptyInput {
1163 operation: "evaluate_parallel",
1164 });
1165 }
1166
1167 let width = bands[0].width();
1169 let height = bands[0].height();
1170 for band in bands.iter().skip(1) {
1171 if band.width() != width || band.height() != height {
1172 return Err(AlgorithmError::InvalidDimensions {
1173 message: "All bands must have same dimensions",
1174 actual: band.width() as usize,
1175 expected: width as usize,
1176 });
1177 }
1178 }
1179
1180 let mut lexer = Lexer::new(expression);
1182 let tokens = lexer.tokenize()?;
1183
1184 let mut parser = Parser::new(tokens);
1186 let expr = parser.parse()?;
1187
1188 let expr = Optimizer::optimize(expr);
1190
1191 let evaluator = Evaluator::new(bands);
1193
1194 let mut result = RasterBuffer::zeros(width, height, bands[0].data_type());
1196
1197 let row_data: Result<Vec<Vec<f64>>> = (0..height)
1199 .into_par_iter()
1200 .map(|y| {
1201 let mut row = Vec::with_capacity(width as usize);
1202 for x in 0..width {
1203 let value = evaluator.eval_pixel(&expr, x, y)?;
1204 row.push(value);
1205 }
1206 Ok(row)
1207 })
1208 .collect();
1209
1210 let row_data = row_data?;
1211
1212 for (y, row) in row_data.iter().enumerate() {
1214 for (x, &value) in row.iter().enumerate() {
1215 result
1216 .set_pixel(x as u64, y as u64, value)
1217 .map_err(AlgorithmError::Core)?;
1218 }
1219 }
1220
1221 Ok(result)
1222 }
1223
1224 pub fn apply_binary(
1226 a: &RasterBuffer,
1227 b: &RasterBuffer,
1228 op: RasterExpression,
1229 ) -> Result<RasterBuffer> {
1230 if a.width() != b.width() || a.height() != b.height() {
1231 return Err(AlgorithmError::InvalidDimensions {
1232 message: "Rasters must have same dimensions",
1233 actual: a.width() as usize,
1234 expected: b.width() as usize,
1235 });
1236 }
1237
1238 let mut result = RasterBuffer::zeros(a.width(), a.height(), a.data_type());
1239
1240 for y in 0..a.height() {
1241 for x in 0..a.width() {
1242 let val_a = a.get_pixel(x, y).map_err(AlgorithmError::Core)?;
1243 let val_b = b.get_pixel(x, y).map_err(AlgorithmError::Core)?;
1244
1245 let val = match op {
1246 RasterExpression::Add => val_a + val_b,
1247 RasterExpression::Subtract => val_a - val_b,
1248 RasterExpression::Multiply => val_a * val_b,
1249 RasterExpression::Divide => {
1250 if val_b.abs() < f64::EPSILON {
1251 f64::NAN
1252 } else {
1253 val_a / val_b
1254 }
1255 }
1256 RasterExpression::Max => val_a.max(val_b),
1257 RasterExpression::Min => val_a.min(val_b),
1258 };
1259
1260 result.set_pixel(x, y, val).map_err(AlgorithmError::Core)?;
1261 }
1262 }
1263
1264 Ok(result)
1265 }
1266
1267 pub fn apply_unary<F>(src: &RasterBuffer, func: F) -> Result<RasterBuffer>
1269 where
1270 F: Fn(f64) -> f64,
1271 {
1272 let mut result = RasterBuffer::zeros(src.width(), src.height(), src.data_type());
1273
1274 for y in 0..src.height() {
1275 for x in 0..src.width() {
1276 let val = src.get_pixel(x, y).map_err(AlgorithmError::Core)?;
1277 let new_val = func(val);
1278 result
1279 .set_pixel(x, y, new_val)
1280 .map_err(AlgorithmError::Core)?;
1281 }
1282 }
1283
1284 Ok(result)
1285 }
1286}
1287
1288#[derive(Debug, Clone, Copy, PartialEq)]
1290pub enum RasterExpression {
1291 Add,
1293 Subtract,
1295 Multiply,
1297 Divide,
1299 Max,
1301 Min,
1303}
1304
1305#[cfg(test)]
1306#[allow(clippy::panic, clippy::cloned_ref_to_slice_refs)]
1307mod tests {
1308 use super::*;
1309 use oxigdal_core::types::RasterDataType;
1310
1311 #[test]
1314 fn test_simple_arithmetic() {
1315 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1316 let mut b2 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1317
1318 for y in 0..5 {
1319 for x in 0..5 {
1320 b1.set_pixel(x, y, 10.0).ok();
1321 b2.set_pixel(x, y, 5.0).ok();
1322 }
1323 }
1324
1325 let result = RasterCalculator::evaluate("B1 + B2", &[b1, b2]);
1326 assert!(result.is_ok());
1327 let r = result.expect("Result should be ok");
1328 let val = r.get_pixel(0, 0).expect("Should get pixel");
1329 assert!((val - 15.0).abs() < f64::EPSILON);
1330 }
1331
1332 #[test]
1333 fn test_ndvi() {
1334 let mut nir = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1335 let mut red = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1336
1337 for y in 0..5 {
1338 for x in 0..5 {
1339 nir.set_pixel(x, y, 100.0).ok();
1340 red.set_pixel(x, y, 50.0).ok();
1341 }
1342 }
1343
1344 let result = RasterCalculator::evaluate("(B1 - B2) / (B1 + B2)", &[nir, red]);
1345 assert!(result.is_ok());
1346 let r = result.expect("Result should be ok");
1347 let val = r.get_pixel(0, 0).expect("Should get pixel");
1348 let expected = (100.0 - 50.0) / (100.0 + 50.0);
1349 assert!((val - expected).abs() < 0.001);
1350 }
1351
1352 #[test]
1353 fn test_math_functions() {
1354 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1355
1356 for y in 0..5 {
1357 for x in 0..5 {
1358 b1.set_pixel(x, y, 16.0).ok();
1359 }
1360 }
1361
1362 let result = RasterCalculator::evaluate("sqrt(B1)", &[b1]);
1363 assert!(result.is_ok());
1364 let r = result.expect("Result should be ok");
1365 let val = r.get_pixel(0, 0).expect("Should get pixel");
1366 assert!((val - 4.0).abs() < f64::EPSILON);
1367 }
1368
1369 #[test]
1370 fn test_conditional() {
1371 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1372
1373 for y in 0..5 {
1374 for x in 0..5 {
1375 b1.set_pixel(x, y, (x * 10) as f64).ok();
1376 }
1377 }
1378
1379 let result = RasterCalculator::evaluate("if B1 > 20 then 1 else 0", &[b1]);
1380 assert!(result.is_ok());
1381 let r = result.expect("Result should be ok");
1382
1383 let val0 = r.get_pixel(0, 0).expect("Should get pixel");
1384 assert!((val0 - 0.0).abs() < f64::EPSILON);
1385
1386 let val3 = r.get_pixel(3, 0).expect("Should get pixel");
1387 assert!((val3 - 1.0).abs() < f64::EPSILON);
1388 }
1389
1390 #[test]
1391 fn test_legacy_add() {
1392 let mut a = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1393 let mut b = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1394
1395 a.set_pixel(0, 0, 10.0).ok();
1396 b.set_pixel(0, 0, 5.0).ok();
1397
1398 let result = RasterCalculator::apply_binary(&a, &b, RasterExpression::Add);
1399 assert!(result.is_ok());
1400 }
1401
1402 #[test]
1405 fn test_empty_bands() {
1406 let result = RasterCalculator::evaluate("B1 + B2", &[]);
1407 assert!(result.is_err());
1408 if let Err(AlgorithmError::EmptyInput { .. }) = result {
1409 } else {
1411 panic!("Expected EmptyInput error");
1412 }
1413 }
1414
1415 #[test]
1416 fn test_single_pixel() {
1417 let mut b1 = RasterBuffer::zeros(1, 1, RasterDataType::Float32);
1418 b1.set_pixel(0, 0, 42.0).ok();
1419
1420 let result = RasterCalculator::evaluate("B1 * 2", &[b1]);
1421 assert!(result.is_ok());
1422 let r = result.expect("Should succeed");
1423 let val = r.get_pixel(0, 0).expect("Should get pixel");
1424 assert!((val - 84.0).abs() < f64::EPSILON);
1425 }
1426
1427 #[test]
1428 fn test_division_by_zero() {
1429 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1430 let mut b2 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1431
1432 for y in 0..3 {
1433 for x in 0..3 {
1434 b1.set_pixel(x, y, 10.0).ok();
1435 b2.set_pixel(x, y, 0.0).ok();
1436 }
1437 }
1438
1439 let result = RasterCalculator::evaluate("B1 / B2", &[b1, b2]);
1440 assert!(result.is_ok());
1441 let r = result.expect("Should succeed");
1442 let val = r.get_pixel(0, 0).expect("Should get pixel");
1443 assert!(val.is_nan()); }
1445
1446 #[test]
1447 fn test_mismatched_dimensions() {
1448 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1449 let b2 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1450
1451 let result = RasterCalculator::evaluate("B1 + B2", &[b1, b2]);
1452 assert!(result.is_err());
1453 if let Err(AlgorithmError::InvalidDimensions { .. }) = result {
1454 } else {
1456 panic!("Expected InvalidDimensions error");
1457 }
1458 }
1459
1460 #[test]
1463 fn test_invalid_band_reference() {
1464 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1465
1466 let result = RasterCalculator::evaluate("B5 + B1", &[b1]);
1467 assert!(result.is_err());
1468 }
1469
1470 #[test]
1471 fn test_undefined_function() {
1472 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1473
1474 let result = RasterCalculator::evaluate("undefined_func(B1)", &[b1]);
1475 assert!(result.is_err());
1476 }
1477
1478 #[test]
1479 fn test_invalid_expression() {
1480 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1481
1482 let result = RasterCalculator::evaluate("B1 +", &[b1]);
1483 assert!(result.is_err());
1484 }
1485
1486 #[test]
1487 fn test_mismatched_parentheses() {
1488 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1489
1490 let result = RasterCalculator::evaluate("(B1 + 10", &[b1]);
1491 assert!(result.is_err());
1492 }
1493
1494 #[test]
1495 fn test_wrong_function_arity() {
1496 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1497
1498 let result = RasterCalculator::evaluate("sqrt(B1, B1)", &[b1]);
1499 assert!(result.is_err());
1500 }
1501
1502 #[test]
1505 fn test_nested_functions() {
1506 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1507
1508 for y in 0..5 {
1509 for x in 0..5 {
1510 b1.set_pixel(x, y, 9.0).ok();
1511 }
1512 }
1513
1514 let result = RasterCalculator::evaluate("sqrt(sqrt(B1))", &[b1]);
1515 assert!(result.is_ok());
1516 let r = result.expect("Should succeed");
1517 let val = r.get_pixel(0, 0).expect("Should get pixel");
1518 let expected = 9.0_f64.sqrt().sqrt();
1519 assert!((val - expected).abs() < 0.001);
1520 }
1521
1522 #[test]
1523 fn test_complex_expression() {
1524 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1525 let mut b2 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1526 let mut b3 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1527
1528 for y in 0..3 {
1529 for x in 0..3 {
1530 b1.set_pixel(x, y, 10.0).ok();
1531 b2.set_pixel(x, y, 5.0).ok();
1532 b3.set_pixel(x, y, 2.0).ok();
1533 }
1534 }
1535
1536 let result = RasterCalculator::evaluate("(B1 + B2) * B3 - sqrt(B1)", &[b1, b2, b3]);
1537 assert!(result.is_ok());
1538 let r = result.expect("Should succeed");
1539 let val = r.get_pixel(0, 0).expect("Should get pixel");
1540 let expected = (10.0 + 5.0) * 2.0 - 10.0_f64.sqrt();
1541 assert!((val - expected).abs() < 0.001);
1542 }
1543
1544 #[test]
1545 fn test_all_math_functions() {
1546 let mut b1 = RasterBuffer::zeros(2, 2, RasterDataType::Float32);
1547
1548 for y in 0..2 {
1549 for x in 0..2 {
1550 b1.set_pixel(x, y, 2.5).ok();
1551 }
1552 }
1553
1554 let functions = vec![
1556 ("abs(B1)", 2.5),
1557 ("floor(B1)", 2.0),
1558 ("ceil(B1)", 3.0),
1559 ("round(B1)", 3.0), ("exp(B1)", 2.5_f64.exp()),
1561 ("log(B1)", 2.5_f64.ln()),
1562 ("log10(B1)", 2.5_f64.log10()),
1563 ("sqrt(B1)", 2.5_f64.sqrt()),
1564 ("sin(B1)", 2.5_f64.sin()),
1565 ("cos(B1)", 2.5_f64.cos()),
1566 ("tan(B1)", 2.5_f64.tan()),
1567 ];
1568
1569 for (expr, expected) in functions {
1570 let result = RasterCalculator::evaluate(expr, &[b1.clone()]);
1571 assert!(result.is_ok(), "Failed for expression: {}", expr);
1572 let r = result.expect("Should succeed");
1573 let val = r.get_pixel(0, 0).expect("Should get pixel");
1574 assert!(
1575 (val - expected).abs() < 0.001,
1576 "Expression {} expected {} but got {}",
1577 expr,
1578 expected,
1579 val
1580 );
1581 }
1582 }
1583
1584 #[test]
1585 fn test_min_max_functions() {
1586 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1587 let mut b2 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1588
1589 for y in 0..3 {
1590 for x in 0..3 {
1591 b1.set_pixel(x, y, 10.0).ok();
1592 b2.set_pixel(x, y, 20.0).ok();
1593 }
1594 }
1595
1596 let result = RasterCalculator::evaluate("min(B1, B2)", &[b1.clone(), b2.clone()]);
1597 assert!(result.is_ok());
1598 let r = result.expect("Should succeed");
1599 let val = r.get_pixel(0, 0).expect("Should get pixel");
1600 assert!((val - 10.0).abs() < f64::EPSILON);
1601
1602 let result = RasterCalculator::evaluate("max(B1, B2)", &[b1, b2]);
1603 assert!(result.is_ok());
1604 let r = result.expect("Should succeed");
1605 let val = r.get_pixel(0, 0).expect("Should get pixel");
1606 assert!((val - 20.0).abs() < f64::EPSILON);
1607 }
1608
1609 #[test]
1610 fn test_power_operation() {
1611 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1612
1613 for y in 0..3 {
1614 for x in 0..3 {
1615 b1.set_pixel(x, y, 2.0).ok();
1616 }
1617 }
1618
1619 let result = RasterCalculator::evaluate("B1 ^ 3", &[b1]);
1620 assert!(result.is_ok());
1621 let r = result.expect("Should succeed");
1622 let val = r.get_pixel(0, 0).expect("Should get pixel");
1623 assert!((val - 8.0).abs() < f64::EPSILON);
1624 }
1625
1626 #[test]
1627 fn test_comparison_operators() {
1628 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1629
1630 for y in 0..3 {
1631 for x in 0..3 {
1632 b1.set_pixel(x, y, 10.0).ok();
1633 }
1634 }
1635
1636 let tests = vec![
1637 ("B1 > 5", 1.0),
1638 ("B1 < 5", 0.0),
1639 ("B1 >= 10", 1.0),
1640 ("B1 <= 10", 1.0),
1641 ("B1 == 10", 1.0),
1642 ("B1 != 5", 1.0),
1643 ];
1644
1645 for (expr, expected) in tests {
1646 let result = RasterCalculator::evaluate(expr, &[b1.clone()]);
1647 assert!(result.is_ok(), "Failed for expression: {}", expr);
1648 let r = result.expect("Should succeed");
1649 let val = r.get_pixel(0, 0).expect("Should get pixel");
1650 assert!(
1651 (val - expected).abs() < f64::EPSILON,
1652 "Expression {} expected {} but got {}",
1653 expr,
1654 expected,
1655 val
1656 );
1657 }
1658 }
1659
1660 #[test]
1661 fn test_logical_operators() {
1662 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1663
1664 for y in 0..3 {
1665 for x in 0..3 {
1666 b1.set_pixel(x, y, 10.0).ok();
1667 }
1668 }
1669
1670 let result = RasterCalculator::evaluate("B1 > 5 and B1 < 15", &[b1.clone()]);
1671 assert!(result.is_ok());
1672 let r = result.expect("Should succeed");
1673 let val = r.get_pixel(0, 0).expect("Should get pixel");
1674 assert!((val - 1.0).abs() < f64::EPSILON);
1675
1676 let result = RasterCalculator::evaluate("B1 < 5 or B1 > 5", &[b1]);
1677 assert!(result.is_ok());
1678 let r = result.expect("Should succeed");
1679 let val = r.get_pixel(0, 0).expect("Should get pixel");
1680 assert!((val - 1.0).abs() < f64::EPSILON);
1681 }
1682
1683 #[test]
1684 fn test_nested_conditionals() {
1685 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1686
1687 for y in 0..3 {
1688 for x in 0..3 {
1689 b1.set_pixel(x, y, (x * 10) as f64).ok();
1690 }
1691 }
1692
1693 let result =
1695 RasterCalculator::evaluate("if B1 > 15 then 3 else (if B1 > 5 then 2 else 1)", &[b1]);
1696 assert!(result.is_ok());
1697 let r = result.expect("Should succeed");
1698
1699 let val0 = r.get_pixel(0, 0).expect("Should get pixel");
1700 assert!((val0 - 1.0).abs() < f64::EPSILON);
1701
1702 let val1 = r.get_pixel(1, 0).expect("Should get pixel");
1703 assert!((val1 - 2.0).abs() < f64::EPSILON);
1704
1705 let val2 = r.get_pixel(2, 0).expect("Should get pixel");
1706 assert!((val2 - 3.0).abs() < f64::EPSILON);
1707 }
1708
1709 #[test]
1712 fn test_legacy_operations() {
1713 let mut a = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1714 let mut b = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1715
1716 for y in 0..3 {
1717 for x in 0..3 {
1718 a.set_pixel(x, y, 10.0).ok();
1719 b.set_pixel(x, y, 5.0).ok();
1720 }
1721 }
1722
1723 let operations = vec![
1724 (RasterExpression::Add, 15.0),
1725 (RasterExpression::Subtract, 5.0),
1726 (RasterExpression::Multiply, 50.0),
1727 (RasterExpression::Divide, 2.0),
1728 (RasterExpression::Max, 10.0),
1729 (RasterExpression::Min, 5.0),
1730 ];
1731
1732 for (op, expected) in operations {
1733 let result = RasterCalculator::apply_binary(&a, &b, op);
1734 assert!(result.is_ok());
1735 let r = result.expect("Should succeed");
1736 let val = r.get_pixel(0, 0).expect("Should get pixel");
1737 assert!(
1738 (val - expected).abs() < f64::EPSILON,
1739 "Operation {:?} expected {} but got {}",
1740 op,
1741 expected,
1742 val
1743 );
1744 }
1745 }
1746
1747 #[test]
1748 fn test_legacy_unary() {
1749 let mut src = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1750
1751 for y in 0..3 {
1752 for x in 0..3 {
1753 src.set_pixel(x, y, 5.0).ok();
1754 }
1755 }
1756
1757 let result = RasterCalculator::apply_unary(&src, |x| x * 2.0);
1758 assert!(result.is_ok());
1759 let r = result.expect("Should succeed");
1760 let val = r.get_pixel(0, 0).expect("Should get pixel");
1761 assert!((val - 10.0).abs() < f64::EPSILON);
1762 }
1763
1764 #[test]
1765 fn test_unary_negate() {
1766 let mut b1 = RasterBuffer::zeros(3, 3, RasterDataType::Float32);
1767
1768 for y in 0..3 {
1769 for x in 0..3 {
1770 b1.set_pixel(x, y, 10.0).ok();
1771 }
1772 }
1773
1774 let result = RasterCalculator::evaluate("-B1", &[b1]);
1775 assert!(result.is_ok());
1776 let r = result.expect("Should succeed");
1777 let val = r.get_pixel(0, 0).expect("Should get pixel");
1778 assert!((val + 10.0).abs() < f64::EPSILON);
1779 }
1780
1781 #[test]
1784 fn test_optimizer_constant_folding() {
1785 let b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1786
1787 let result = RasterCalculator::evaluate("2 + 3", &[b1.clone()]);
1789 assert!(result.is_ok());
1790 let r = result.expect("Should succeed");
1791 let val = r.get_pixel(0, 0).expect("Should get pixel");
1792 assert!((val - 5.0).abs() < f64::EPSILON);
1793
1794 let result = RasterCalculator::evaluate("sqrt(16)", &[b1.clone()]);
1796 assert!(result.is_ok());
1797 let r = result.expect("Should succeed");
1798 let val = r.get_pixel(0, 0).expect("Should get pixel");
1799 assert!((val - 4.0).abs() < f64::EPSILON);
1800
1801 let mut b2 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1803 for y in 0..5 {
1804 for x in 0..5 {
1805 b2.set_pixel(x, y, 10.0).ok();
1806 }
1807 }
1808 let result = RasterCalculator::evaluate("B1 + (2 + 3)", &[b2]);
1809 assert!(result.is_ok());
1810 let r = result.expect("Should succeed");
1811 let val = r.get_pixel(0, 0).expect("Should get pixel");
1812 assert!((val - 15.0).abs() < f64::EPSILON);
1813 }
1814
1815 #[test]
1816 fn test_optimizer_algebraic_simplification() {
1817 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1818 for y in 0..5 {
1819 for x in 0..5 {
1820 b1.set_pixel(x, y, 10.0).ok();
1821 }
1822 }
1823
1824 let result = RasterCalculator::evaluate("B1 + 0", &[b1.clone()]);
1826 assert!(result.is_ok());
1827 let r = result.expect("Should succeed");
1828 let val = r.get_pixel(0, 0).expect("Should get pixel");
1829 assert!((val - 10.0).abs() < f64::EPSILON);
1830
1831 let result = RasterCalculator::evaluate("B1 * 1", &[b1.clone()]);
1833 assert!(result.is_ok());
1834 let r = result.expect("Should succeed");
1835 let val = r.get_pixel(0, 0).expect("Should get pixel");
1836 assert!((val - 10.0).abs() < f64::EPSILON);
1837
1838 let result = RasterCalculator::evaluate("B1 * 0", &[b1.clone()]);
1840 assert!(result.is_ok());
1841 let r = result.expect("Should succeed");
1842 let val = r.get_pixel(0, 0).expect("Should get pixel");
1843 assert!(val.abs() < f64::EPSILON);
1844
1845 let result = RasterCalculator::evaluate("B1 ^ 1", &[b1]);
1847 assert!(result.is_ok());
1848 let r = result.expect("Should succeed");
1849 let val = r.get_pixel(0, 0).expect("Should get pixel");
1850 assert!((val - 10.0).abs() < f64::EPSILON);
1851 }
1852
1853 #[test]
1854 fn test_optimizer_conditional_constant() {
1855 let mut b1 = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
1856 for y in 0..5 {
1857 for x in 0..5 {
1858 b1.set_pixel(x, y, 10.0).ok();
1859 }
1860 }
1861
1862 let result = RasterCalculator::evaluate("if 1 then B1 else B1 * 2", &[b1.clone()]);
1864 assert!(result.is_ok());
1865 let r = result.expect("Should succeed");
1866 let val = r.get_pixel(0, 0).expect("Should get pixel");
1867 assert!((val - 10.0).abs() < f64::EPSILON);
1868
1869 let result = RasterCalculator::evaluate("if 0 then B1 else B1 * 2", &[b1]);
1871 assert!(result.is_ok());
1872 let r = result.expect("Should succeed");
1873 let val = r.get_pixel(0, 0).expect("Should get pixel");
1874 assert!((val - 20.0).abs() < f64::EPSILON);
1875 }
1876
1877 #[test]
1880 #[cfg(feature = "parallel")]
1881 fn test_parallel_evaluation() {
1882 let mut b1 = RasterBuffer::zeros(100, 100, RasterDataType::Float32);
1883 let mut b2 = RasterBuffer::zeros(100, 100, RasterDataType::Float32);
1884
1885 for y in 0..100 {
1886 for x in 0..100 {
1887 b1.set_pixel(x, y, (x + y) as f64).ok();
1888 b2.set_pixel(x, y, (x * y) as f64).ok();
1889 }
1890 }
1891
1892 let result = RasterCalculator::evaluate_parallel("B1 + B2", &[b1.clone(), b2.clone()]);
1893 assert!(result.is_ok());
1894 let r = result.expect("Should succeed");
1895
1896 for y in 0..100 {
1898 for x in 0..100 {
1899 let val = r.get_pixel(x, y).expect("Should get pixel");
1900 let expected = (x + y) as f64 + (x * y) as f64;
1901 assert!(
1902 (val - expected).abs() < f64::EPSILON,
1903 "Mismatch at ({}, {}): expected {}, got {}",
1904 x,
1905 y,
1906 expected,
1907 val
1908 );
1909 }
1910 }
1911 }
1912
1913 #[test]
1914 #[cfg(feature = "parallel")]
1915 fn test_parallel_complex_expression() {
1916 let mut nir = RasterBuffer::zeros(50, 50, RasterDataType::Float32);
1917 let mut red = RasterBuffer::zeros(50, 50, RasterDataType::Float32);
1918
1919 for y in 0..50 {
1920 for x in 0..50 {
1921 nir.set_pixel(x, y, 100.0 + x as f64).ok();
1922 red.set_pixel(x, y, 50.0 + y as f64).ok();
1923 }
1924 }
1925
1926 let result = RasterCalculator::evaluate_parallel(
1927 "(B1 - B2) / (B1 + B2)",
1928 &[nir.clone(), red.clone()],
1929 );
1930 assert!(result.is_ok());
1931 let r = result.expect("Should succeed");
1932
1933 for y in 0..50 {
1935 for x in 0..50 {
1936 let nir_val = 100.0 + x as f64;
1937 let red_val = 50.0 + y as f64;
1938 let expected = (nir_val - red_val) / (nir_val + red_val);
1939 let val = r.get_pixel(x, y).expect("Should get pixel");
1940 assert!(
1941 (val - expected).abs() < 0.001,
1942 "NDVI mismatch at ({}, {}): expected {}, got {}",
1943 x,
1944 y,
1945 expected,
1946 val
1947 );
1948 }
1949 }
1950 }
1951
1952 #[test]
1953 #[cfg(feature = "parallel")]
1954 fn test_parallel_with_optimization() {
1955 let mut b1 = RasterBuffer::zeros(50, 50, RasterDataType::Float32);
1956 for y in 0..50 {
1957 for x in 0..50 {
1958 b1.set_pixel(x, y, x as f64).ok();
1959 }
1960 }
1961
1962 let result = RasterCalculator::evaluate_parallel("B1 * 1 + 0 + sqrt(16)", &[b1]);
1964 assert!(result.is_ok());
1965 let r = result.expect("Should succeed");
1966
1967 for y in 0..50 {
1968 for x in 0..50 {
1969 let val = r.get_pixel(x, y).expect("Should get pixel");
1970 let expected = x as f64 + 4.0; assert!(
1972 (val - expected).abs() < f64::EPSILON,
1973 "Mismatch at ({}, {}): expected {}, got {}",
1974 x,
1975 y,
1976 expected,
1977 val
1978 );
1979 }
1980 }
1981 }
1982}