Skip to main content

runmat_runtime/
comparison.rs

1//! Comparison operations for language-compatible logic
2//!
3//! Implements comparison operators returning logical matrices/values.
4
5use std::cmp::Ordering;
6
7use runmat_value::Tensor;
8
9use crate::builtins::common::tensor::tensor_values_f64_cow;
10use crate::builtins::logical::rel::integer_comparison::{
11    compare_integer_values, integer_f64_order, matches_optional_relation, matches_relation,
12    storage_value, IntegerComparisonOp,
13};
14
15/// Element-wise greater than comparison
16pub fn matrix_gt(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
17    matrix_compare(a, b, ">", IntegerComparisonOp::Gt, |x, y| x > y)
18}
19
20/// Element-wise greater than or equal comparison
21pub fn matrix_ge(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
22    matrix_compare(a, b, ">=", IntegerComparisonOp::Ge, |x, y| x >= y)
23}
24
25/// Element-wise less than comparison
26pub fn matrix_lt(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
27    matrix_compare(a, b, "<", IntegerComparisonOp::Lt, |x, y| x < y)
28}
29
30/// Element-wise less than or equal comparison
31pub fn matrix_le(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
32    matrix_compare(a, b, "<=", IntegerComparisonOp::Le, |x, y| x <= y)
33}
34
35/// Element-wise equality comparison
36pub fn matrix_eq(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
37    matrix_compare(a, b, "==", IntegerComparisonOp::Eq, |x, y| x == y)
38}
39
40/// Element-wise inequality comparison
41pub fn matrix_ne(a: &Tensor, b: &Tensor) -> Result<Tensor, String> {
42    matrix_compare(a, b, "!=", IntegerComparisonOp::Ne, |x, y| x != y)
43}
44
45fn matrix_compare(
46    a: &Tensor,
47    b: &Tensor,
48    symbol: &str,
49    operation: IntegerComparisonOp,
50    float_compare: impl Fn(f64, f64) -> bool,
51) -> Result<Tensor, String> {
52    if a.rows() != b.rows() || a.cols() != b.cols() {
53        return Err(format!(
54            "Matrix dimensions must agree: {}x{} {} {}x{}",
55            a.rows(),
56            a.cols(),
57            symbol,
58            b.rows(),
59            b.cols()
60        ));
61    }
62
63    let data: Vec<f64> = match (a.integer_storage(), b.integer_storage()) {
64        (Some(left), Some(right)) => (0..left.len())
65            .map(|index| {
66                let ordering =
67                    compare_integer_values(storage_value(left, index), storage_value(right, index));
68                logical_f64(matches_relation(ordering, operation))
69            })
70            .collect(),
71        (Some(left), None) => {
72            let right = tensor_values_f64_cow(b);
73            (0..left.len())
74                .map(|index| {
75                    logical_f64(matches_optional_relation(
76                        integer_f64_order(storage_value(left, index), right[index]),
77                        operation,
78                    ))
79                })
80                .collect()
81        }
82        (None, Some(right)) => {
83            let left = tensor_values_f64_cow(a);
84            (0..right.len())
85                .map(|index| {
86                    let ordering = integer_f64_order(storage_value(right, index), left[index])
87                        .map(Ordering::reverse);
88                    logical_f64(matches_optional_relation(ordering, operation))
89                })
90                .collect()
91        }
92        (None, None) => {
93            let left = tensor_values_f64_cow(a);
94            let right = tensor_values_f64_cow(b);
95            left.iter()
96                .zip(right.iter())
97                .map(|(x, y)| logical_f64(float_compare(*x, *y)))
98                .collect()
99        }
100    };
101
102    Tensor::new_2d(data, a.rows(), a.cols())
103}
104
105fn logical_f64(value: bool) -> f64 {
106    if value {
107        1.0
108    } else {
109        0.0
110    }
111}