Skip to main content

pictorus_block_data/
lib.rs

1//! This crate contains deprecated code for passing data between blocks.
2//! We are in the process of phasing this out in favor of an approach that
3//! allows us to pass data around without the use of dynamic heap allocations.
4#![no_std]
5
6extern crate alloc;
7
8mod block_ops;
9
10use alloc::borrow::ToOwned;
11use alloc::string::{String, ToString};
12use alloc::vec::Vec;
13use core::cmp::Ordering;
14use num_traits::Float;
15
16use miniserde::json::{self, Array, Number, Value};
17use nalgebra::iter::MatrixIter;
18use nalgebra::{DMatrix, SVD};
19
20use pictorus_traits::custom_blocks::{BlockDataRead, BlockDataWrite};
21use pictorus_traits::{ByteSliceSignal, PassBy};
22
23#[derive(Clone, Debug, PartialEq, Copy, strum::EnumString)]
24pub enum BlockDataType {
25    BytesArray,
26    Scalar,
27    Vector,
28    Matrix,
29}
30
31pub enum BlockTypeRelationship {
32    SameSizes,
33    FirstIsScalar,
34    SecondIsScalar,
35    None,
36}
37
38#[derive(Clone, Debug, PartialEq)]
39pub struct BlockData {
40    _data: DMatrix<f64>,
41    _type: BlockDataType,
42}
43
44impl BlockDataRead for BlockData {
45    fn get_scalar(&self) -> f64 {
46        self.scalar()
47    }
48
49    fn get_matrix(&self) -> (usize, usize, &[f64]) {
50        (self.nrows(), self.ncols(), self._data.as_slice())
51    }
52}
53
54impl BlockDataRead for &BlockData {
55    fn get_scalar(&self) -> f64 {
56        self.scalar()
57    }
58
59    fn get_matrix(&self) -> (usize, usize, &[f64]) {
60        (self.nrows(), self.ncols(), self._data.as_slice())
61    }
62}
63
64impl BlockDataWrite for &mut BlockData {
65    fn set_scalar_value(&mut self, scalar: f64) {
66        self.set_scalar(scalar);
67    }
68
69    fn set_matrix_value(&mut self, nrows: usize, ncols: usize, data: &[f64]) {
70        self._data = DMatrix::from_column_slice(nrows, ncols, data);
71        self._type = determine_data_type(nrows, ncols);
72    }
73}
74
75pub fn determine_data_type(nrows: usize, ncols: usize) -> BlockDataType {
76    if nrows == 1 && ncols == 1 {
77        BlockDataType::Scalar
78    } else if nrows == 1 {
79        BlockDataType::Vector
80    } else {
81        BlockDataType::Matrix
82    }
83}
84
85fn create_byte_row(byte_data: &[u8]) -> DMatrix<f64> {
86    let data: Vec<f64> = byte_data.iter().map(|&v| v as f64).collect();
87    DMatrix::from_row_slice(1, data.len(), &data)
88}
89
90impl BlockData {
91    pub fn new(rows: usize, cols: usize, data: &[f64]) -> Self {
92        Self::from_row_slice(rows, cols, data)
93    }
94
95    pub fn from_data(data: DMatrix<f64>, dtype: BlockDataType) -> Self {
96        Self {
97            _data: data,
98            _type: dtype,
99        }
100    }
101    pub fn from_element(nrows: usize, ncols: usize, scalar: f64) -> Self {
102        Self::from_data(
103            DMatrix::from_element(nrows, ncols, scalar),
104            determine_data_type(nrows, ncols),
105        )
106    }
107    pub fn from_scalar(scalar: f64) -> Self {
108        Self::new(1, 1, &[scalar])
109    }
110    pub fn from_row_slice(nrows: usize, ncols: usize, data: &[f64]) -> Self {
111        Self::from_data(
112            DMatrix::from_row_slice(nrows, ncols, data),
113            determine_data_type(nrows, ncols),
114        )
115    }
116
117    pub fn from_bytes(byte_data: &[u8]) -> Self {
118        Self::from_data(create_byte_row(byte_data), BlockDataType::BytesArray)
119    }
120
121    pub fn scalar_sizeof(scalar: f64, block: &BlockData) -> Self {
122        Self::from_element(block.nrows(), block.ncols(), scalar)
123    }
124
125    pub fn from_vector(data: &[f64]) -> Self {
126        Self::new(1, data.len(), data)
127    }
128
129    pub fn from_matrix(matrix_slice: &[&[f64]]) -> Self {
130        let rows = matrix_slice.len();
131        let cols = if rows > 0 { matrix_slice[0].len() } else { 0 };
132
133        Self::from_data(
134            DMatrix::from_row_iterator(rows, cols, matrix_slice.concat()),
135            BlockDataType::Matrix,
136        )
137    }
138
139    pub fn zeros_sizeof(block: &BlockData) -> Self {
140        Self::from_element(block.nrows(), block.ncols(), 0.0)
141    }
142    pub fn ones_sizeof(block: &BlockData) -> Self {
143        Self::from_element(block.nrows(), block.ncols(), 1.0)
144    }
145
146    pub fn scalar_from_bool(value: bool) -> Self {
147        let value = if value { 1.0 } else { 0.0 };
148        Self::from_scalar(value)
149    }
150
151    pub fn fix_non_finite(&mut self) {
152        self._data = self._data.map(|x| {
153            if x.is_nan() || x == f64::INFINITY || x == f64::NEG_INFINITY {
154                0.0
155            } else {
156                x
157            }
158        });
159    }
160
161    pub fn slice(&mut self, r0: usize, c0: usize, rows: usize, cols: usize) -> Self {
162        let slice = self._data.view((r0, c0), (rows, cols)).to_owned().into();
163        Self::from_data(slice, determine_data_type(rows, cols))
164    }
165
166    pub fn as_col_slice(&self) -> &[f64] {
167        self._data.as_slice()
168    }
169
170    pub fn set(&mut self, index: usize, value: f64) {
171        self._data[index] = value;
172    }
173    pub fn at(&self, index: usize) -> f64 {
174        self._data[index]
175    }
176    pub fn ref_at(&self, index: usize) -> &f64 {
177        &self._data[index]
178    }
179    pub fn ref_at_mut(&mut self, index: usize) -> &mut f64 {
180        &mut self._data[index]
181    }
182    pub fn at_rc(&self, r: usize, c: usize) -> f64 {
183        self._data[(r, c)]
184    }
185    pub fn get_type(&self) -> BlockDataType {
186        self._type
187    }
188    pub fn set_type(&mut self, new_type: BlockDataType) {
189        self._type = new_type;
190    }
191    pub fn scalar(&self) -> f64 {
192        // Scalars just return the (0,0)th element of the matrix
193        match self.get_type() {
194            BlockDataType::Scalar => self.at(0),
195            other => panic!("Cannot treat {:?} as scalar!", other),
196        }
197    }
198    pub fn get_data(&self) -> &DMatrix<f64> {
199        &self._data
200    }
201    pub fn set_data(&mut self, data: DMatrix<f64>) {
202        self._data = data;
203    }
204    pub fn maybe_reset(&mut self, reset_signal: &BlockData) {
205        // Resets elements of data where reset_signal is truthy
206        if reset_signal.any() {
207            self._data = self.component_mul(&reset_signal.logical_not())._data;
208        }
209    }
210    pub fn compare(&self, other: &BlockData) -> BlockTypeRelationship {
211        if self.same_size(other) {
212            return BlockTypeRelationship::SameSizes;
213        } else if self.get_type() == BlockDataType::Scalar {
214            return BlockTypeRelationship::FirstIsScalar;
215        } else if other.get_type() == BlockDataType::Scalar {
216            return BlockTypeRelationship::SecondIsScalar;
217        }
218        BlockTypeRelationship::None
219    }
220    pub fn vector(&self) -> DMatrix<f64> {
221        // Scalars just return the (0,0)th element of the matrix
222        match self.get_type() {
223            BlockDataType::Vector => self.get_data().clone(),
224            _ => panic!("Cannot treat non-scalar BlockData as scalar!"),
225        }
226    }
227
228    pub fn boolean(&self) -> Self {
229        BlockData::component_neq(self, &BlockData::zeros_sizeof(self))
230    }
231
232    pub fn norm(&self) -> f64 {
233        self._data.norm()
234    }
235
236    pub fn vector_magnitude(&self) -> Self {
237        /*
238        Returns a BlockData representing the vector magnitude of each column of Self
239        */
240
241        let mut magnitudes = BlockData::from_element(1, self.ncols(), 0.0);
242        for i in 0..self.ncols() {
243            let column = self._data.column(i);
244            let magnitude = column.norm();
245            magnitudes[i] = magnitude;
246        }
247
248        magnitudes
249    }
250
251    pub fn vector_magnitude_rows(&self) -> Self {
252        /*
253        Returns a BlockData representing the vector magnitude of each row of Self
254        */
255        self.transpose().vector_magnitude()
256    }
257
258    pub fn any(&self) -> bool {
259        self.boolean().sum() > 0.0
260    }
261
262    pub fn all(&self) -> bool {
263        self.boolean().sum() == (self.nrows() * self.ncols()) as f64
264    }
265
266    pub fn set_scalar(&mut self, new_scalar_value: f64) {
267        match self.get_type() {
268            BlockDataType::Scalar => self._data[(0, 0)] = new_scalar_value,
269            _ => panic!("Cannot treat non-scalar BlockData as scalar!"),
270        }
271    }
272    pub fn set_bytes(&mut self, byte_data: &[u8]) {
273        match self.get_type() {
274            BlockDataType::BytesArray => {
275                self._data = create_byte_row(byte_data);
276            }
277            _ => panic!("Cannot treat bytes as numeric data"),
278        }
279    }
280    pub fn set_scalar_bool(&mut self, value: bool) {
281        let value = if value { 1.0 } else { 0.0 };
282        self.set_scalar(value);
283    }
284    pub fn nrows(&self) -> usize {
285        self._data.nrows()
286    }
287    pub fn ncols(&self) -> usize {
288        self._data.ncols()
289    }
290    pub fn size(&self) -> (usize, usize) {
291        (self.nrows(), self.ncols())
292    }
293    pub fn n_elements(&self) -> usize {
294        self.nrows() * self.ncols()
295    }
296    pub fn same_size(&self, other: &BlockData) -> bool {
297        (self.nrows() == other.nrows()) && (self.ncols() == other.ncols())
298    }
299    pub fn inner_dims_same(&self, other: &BlockData) -> bool {
300        self.ncols() == other.nrows()
301    }
302    pub fn component_mul(&self, other: &BlockData) -> Self {
303        match self.compare(other) {
304            BlockTypeRelationship::SameSizes => {
305                BlockData::from_data(self._data.component_mul(&other._data), self._type)
306            }
307            BlockTypeRelationship::FirstIsScalar => {
308                BlockData::from_data(self.scalar() * other.get_data(), other.get_type())
309            }
310            BlockTypeRelationship::SecondIsScalar => {
311                BlockData::from_data(&self._data * other.scalar(), self._type)
312            }
313            _ => panic!(
314                "Cannot perform component-wise multiplication if (a) sizes are not equal or (b) at least one is not scalar."
315            ),
316        }
317    }
318    pub fn component_set(&mut self, condition: &BlockData, assign: &BlockData) {
319        // Conditionally set each element: If "condition" is not falsy, then set to the
320        // value specified in "assign"
321        match condition.compare(assign) {
322            BlockTypeRelationship::SameSizes => {
323                for (idx, condition_val) in condition._data.iter().enumerate() {
324                    if *condition_val != 0.0 {
325                        self._data[idx] = assign.at(idx);
326                    }
327                }
328            }
329            // TODO: Should eventually allow scalar to matrix assignment
330            _ => panic!("Cannot perform component-wise assignment if sizes are not equal."),
331        }
332    }
333    pub fn component_or(first: &BlockData, other: &BlockData) -> Self {
334        match first.compare(other) {
335            BlockTypeRelationship::SameSizes => {
336                let mut result = BlockData::zeros_sizeof(first);
337                for (idx, value) in first._data.iter().enumerate() {
338                    let val = if *value != 0.0 || other.at(idx) != 0.0 {
339                        1.0
340                    } else {
341                        0.0
342                    };
343                    result.set(idx, val);
344                }
345                result
346            }
347            // TODO: Should eventually allow scalar to matrix comparisons
348            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
349        }
350    }
351    pub fn component_and(first: &BlockData, other: &BlockData) -> Self {
352        match first.compare(other) {
353            BlockTypeRelationship::SameSizes => {
354                let mut result = BlockData::zeros_sizeof(first);
355                for (idx, value) in first._data.iter().enumerate() {
356                    let val = if *value != 0.0 && other.at(idx) != 0.0 {
357                        1.0
358                    } else {
359                        0.0
360                    };
361                    result.set(idx, val);
362                }
363                result
364            }
365            // TODO: Should eventually allow scalar to matrix comparisons
366            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
367        }
368    }
369
370    pub fn component_bitand(&self, rhs: &BlockData) -> Self {
371        self.component_map(rhs, |i1, i2| (i1 as i64 & i2 as i64) as f64)
372    }
373
374    pub fn component_bitor(&self, rhs: &BlockData) -> Self {
375        self.component_map(rhs, |i1, i2| (i1 as i64 | i2 as i64) as f64)
376    }
377
378    pub fn component_bitxor(&self, rhs: &BlockData) -> Self {
379        self.component_map(rhs, |i1, i2| (i1 as i64 ^ i2 as i64) as f64)
380    }
381
382    pub fn component_lshift(&self, bits: i32) -> Self {
383        BlockData::from_data(self._data.map(|d| ((d as i64) << bits) as f64), self._type)
384    }
385
386    pub fn component_rshift(&self, bits: i32) -> Self {
387        BlockData::from_data(self._data.map(|d| ((d as i64) >> bits) as f64), self._type)
388    }
389
390    pub fn component_bitnot(&self) -> Self {
391        BlockData::from_data(self._data.map(|d| !(d as i64) as f64), self._type)
392    }
393
394    fn component_map<F>(&self, rhs: &BlockData, f: F) -> BlockData
395    where
396        F: Fn(f64, f64) -> f64,
397    {
398        match self.compare(rhs) {
399            BlockTypeRelationship::SameSizes => {
400                BlockData::from_data(self._data.zip_map(rhs.get_data(), f), self._type)
401            }
402            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
403        }
404    }
405    pub fn component_eq(first: &BlockData, other: &BlockData) -> Self {
406        match first.compare(other) {
407            BlockTypeRelationship::SameSizes => BlockData::from_data(
408                DMatrix::from_fn(first.nrows(), first.ncols(), |i, j| {
409                    (Float::abs(first.at_rc(i, j) - other.at_rc(i, j)) < f64::EPSILON) as u8 as f64
410                }),
411                first.get_type(),
412            ),
413            // TODO: Should eventually allow scalar to matrix comparisons
414            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
415        }
416    }
417    pub fn component_neq(first: &BlockData, other: &BlockData) -> Self {
418        match first.compare(other) {
419            BlockTypeRelationship::SameSizes => BlockData::from_data(
420                DMatrix::from_fn(first.nrows(), first.ncols(), |i, j| {
421                    (Float::abs(first.at_rc(i, j) - other.at_rc(i, j)) >= f64::EPSILON) as u8 as f64
422                }),
423                first.get_type(),
424            ),
425            // TODO: Should eventually allow scalar to matrix comparisons
426            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
427        }
428    }
429
430    pub fn component_gt(first: &BlockData, other: &BlockData) -> Self {
431        match first.compare(other) {
432            BlockTypeRelationship::SameSizes => {
433                let mut result = BlockData::zeros_sizeof(first);
434                for (idx, value) in first._data.iter().enumerate() {
435                    let val = if *value > other.at(idx) { 1.0 } else { 0.0 };
436                    result.set(idx, val);
437                }
438                result
439            }
440            // TODO: Should eventually allow scalar to matrix comparisons
441            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
442        }
443    }
444
445    pub fn component_gte(first: &BlockData, other: &BlockData) -> Self {
446        match first.compare(other) {
447            BlockTypeRelationship::SameSizes => {
448                let mut result = BlockData::zeros_sizeof(first);
449                for (idx, value) in first._data.iter().enumerate() {
450                    let val = if *value >= other.at(idx) { 1.0 } else { 0.0 };
451                    result.set(idx, val);
452                }
453                result
454            }
455            // TODO: Should eventually allow scalar to matrix comparisons
456            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
457        }
458    }
459
460    pub fn component_lt(first: &BlockData, other: &BlockData) -> Self {
461        match first.compare(other) {
462            BlockTypeRelationship::SameSizes => {
463                let mut result = BlockData::zeros_sizeof(first);
464                for (idx, value) in first._data.iter().enumerate() {
465                    let val = if *value < other.at(idx) { 1.0 } else { 0.0 };
466                    result.set(idx, val);
467                }
468                result
469            }
470            // TODO: Should eventually allow scalar to matrix comparisons
471            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
472        }
473    }
474
475    pub fn component_lte(first: &BlockData, other: &BlockData) -> Self {
476        match first.compare(other) {
477            BlockTypeRelationship::SameSizes => {
478                let mut result = BlockData::zeros_sizeof(first);
479                for (idx, value) in first._data.iter().enumerate() {
480                    let val = if *value <= other.at(idx) { 1.0 } else { 0.0 };
481                    result.set(idx, val);
482                }
483                result
484            }
485            // TODO: Should eventually allow scalar to matrix comparisons
486            _ => panic!("Cannot perform component-wise comparisons if sizes are not equal."),
487        }
488    }
489
490    pub fn powf(&self, coefficient: &BlockData) -> Self {
491        // TODO: Nalgebra currently only supports integer exponentiation.
492        // Rolling our own to handle floating point.
493        let mut result = BlockData::zeros_sizeof(self);
494        for (i, value) in self._data.iter().enumerate() {
495            result.set(i, Float::powf(*value, coefficient.at(i)));
496        }
497        result
498    }
499    pub fn sign(&self) -> Self {
500        // Return f64 {1.0, 0.0, -1.0} to represent sign of each element in BlockData
501        // as per numpy convention
502        let mut sign_vals = self.gtz();
503        sign_vals.component_set(&self.ltz(), &BlockData::scalar_sizeof(-1.0, self));
504        sign_vals
505    }
506    pub fn abs(&self) -> Self {
507        BlockData::from_data(self._data.abs(), self._type)
508    }
509    pub fn transpose(&self) -> Self {
510        BlockData::from_data(self._data.transpose(), self._type)
511    }
512    pub fn determinant(&self) -> Self {
513        let det = self._data.determinant();
514        BlockData::from_scalar(det)
515    }
516    pub fn cross(&self, other: &BlockData) -> Self {
517        BlockData::from_data(self._data.cross(&other._data), self._type)
518    }
519    pub fn dot(&self, other: &BlockData) -> Self {
520        let dot: f64 = self._data.dot(&other._data);
521        BlockData::from_scalar(dot)
522    }
523    pub fn inverse(&self) -> Option<Self> {
524        let inverse = self._data.clone().try_inverse()?;
525        Some(BlockData::from_data(inverse, self._type))
526    }
527    pub fn pseudo_inverse(&self, epsilon: f64) -> Option<Self> {
528        let svd = SVD::new(self._data.clone(), true, true);
529        let s = svd.singular_values;
530        let u = svd.u?;
531        let v_t = svd.v_t?;
532        let s_pinv = DMatrix::from_diagonal(&s.map(|x| {
533            if Float::abs(x) > epsilon {
534                1.0 / x
535            } else {
536                0.0
537            }
538        }));
539        let pinv = u * s_pinv * v_t;
540        Some(BlockData::from_data(pinv.transpose(), self._type))
541    }
542    pub fn to_bytes(&self) -> Vec<u8> {
543        match self.get_type() {
544            BlockDataType::BytesArray => self._data.iter().map(|&v| v as u8).collect(),
545            _ => self.stringify().as_bytes().to_vec(),
546        }
547    }
548
549    /// Returns a Vector of bytes representing the raw data
550    pub fn to_raw_bytes(&self) -> Vec<u8> {
551        self._data.iter().map(|&v| v as u8).collect()
552    }
553
554    /// Returns the serde:json::Value equivalent of this data
555    pub fn to_json(&self) -> Value {
556        match self.get_type() {
557            BlockDataType::Scalar => Value::Number(Number::F64(self.scalar())),
558            BlockDataType::BytesArray => {
559                let mut arr = Array::new();
560                self.to_bytes()
561                    .iter()
562                    .for_each(|v| arr.push(Value::Number(Number::U64(*v as u64))));
563                Value::Array(arr)
564            }
565            _ => {
566                let mut arr = Array::new();
567                self._data.row_iter().for_each(|r| {
568                    let mut inner_array = Array::new();
569                    r.iter()
570                        .for_each(|v| inner_array.push(Value::Number(Number::F64(*v))));
571                    arr.push(Value::Array(inner_array));
572                });
573                Value::Array(arr)
574            }
575        }
576    }
577
578    /// Returns the data represented as a valid JSON string
579    pub fn stringify(&self) -> String {
580        json::to_string(&self.to_json())
581    }
582
583    /// Return the raw data represented as a string
584    ///
585    /// This will attempt to convert internal vector data to utf-8. This behaves the same as stringify
586    /// for all data types other than byte arrays, which will attempt to convert to a string.
587    pub fn raw_string(&self) -> String {
588        String::from_utf8(self.to_bytes()).unwrap_or("".to_string())
589    }
590
591    pub fn iter(
592        &self,
593    ) -> MatrixIter<
594        f64,
595        nalgebra::Dyn,
596        nalgebra::Dyn,
597        nalgebra::VecStorage<f64, nalgebra::Dyn, nalgebra::Dyn>,
598    > {
599        self._data.iter()
600    }
601
602    pub fn map<F: FnMut(f64) -> f64>(&self, f: F) -> Self {
603        BlockData::from_data(self._data.map(f), self._type)
604    }
605
606    pub fn sum(&self) -> f64 {
607        self._data.sum()
608    }
609
610    pub fn mean(&self) -> f64 {
611        self.sum() / self.n_elements() as f64
612    }
613
614    pub fn max(&self) -> f64 {
615        self._data.iter().cloned().fold(f64::MIN, f64::max)
616    }
617
618    pub fn min(&self) -> f64 {
619        self._data.iter().cloned().fold(f64::MAX, f64::min)
620    }
621
622    pub fn argmax(&self) -> f64 {
623        self._data
624            .iter()
625            .enumerate()
626            .fold((0, f64::MIN), |(max_idx, max_val), (idx, &val)| {
627                if val > max_val {
628                    (idx, val)
629                } else {
630                    (max_idx, max_val)
631                }
632            })
633            .0 as f64
634    }
635
636    pub fn argmin(&self) -> f64 {
637        self._data
638            .iter()
639            .enumerate()
640            .fold((0, f64::MAX), |(min_idx, min_val), (idx, &val)| {
641                if val < min_val {
642                    (idx, val)
643                } else {
644                    (min_idx, min_val)
645                }
646            })
647            .0 as f64
648    }
649
650    pub fn sorted(&self, ascending: bool) -> Self {
651        let mut sorted_values: Vec<f64> = self._data.iter().copied().collect();
652
653        // sort_unstable_by is more memory efficient, and is only "unstable" in that
654        // it doesn't preserve order of equal values. As this isn't really an issue for
655        // us, we'll take the memory win.
656        sorted_values.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
657
658        if !ascending {
659            sorted_values.reverse();
660        }
661
662        BlockData::from_vector(sorted_values.as_slice())
663    }
664
665    pub fn median(&self) -> f64 {
666        let sorted_values = self.sorted(true);
667        let len = sorted_values.len();
668        if len % 2 == 0 {
669            (sorted_values.at(len / 2 - 1) + sorted_values.at(len / 2)) / 2.0
670        } else {
671            sorted_values.at(len / 2)
672        }
673    }
674
675    pub fn sup(&self, other: &BlockData) -> Self {
676        BlockData::from_data(self._data.sup(&other._data), self._type)
677    }
678
679    pub fn inf(&self, other: &BlockData) -> Self {
680        BlockData::from_data(self._data.inf(&other._data), self._type)
681    }
682
683    pub fn len(&self) -> usize {
684        self._data.len()
685    }
686
687    pub fn is_empty(&self) -> bool {
688        self._data.is_empty()
689    }
690
691    pub fn or(&self, other: &BlockData) -> Self {
692        BlockData::component_or(self, other)
693    }
694
695    pub fn and(&self, other: &BlockData) -> Self {
696        BlockData::component_and(self, other)
697    }
698
699    pub fn eq(&self, other: &BlockData) -> Self {
700        BlockData::component_eq(self, other)
701    }
702
703    pub fn neq(&self, other: &BlockData) -> Self {
704        BlockData::component_neq(self, other)
705    }
706
707    pub fn gt(&self, other: &BlockData) -> Self {
708        BlockData::component_gt(self, other)
709    }
710
711    pub fn gte(&self, other: &BlockData) -> Self {
712        BlockData::component_gte(self, other)
713    }
714
715    pub fn lt(&self, other: &BlockData) -> Self {
716        BlockData::component_lt(self, other)
717    }
718
719    pub fn lte(&self, other: &BlockData) -> Self {
720        BlockData::component_lte(self, other)
721    }
722
723    pub fn logical_not(&self) -> Self {
724        // Not is just checking every value for equality with zero (false)
725        self.eqz()
726    }
727
728    pub fn ltz(&self) -> Self {
729        // Less than zero
730        BlockData::from_data(self._data.map(|d| ((d as i8) < 0) as u8 as f64), self._type)
731    }
732
733    pub fn ltez(&self) -> Self {
734        // Less than or equal to zero
735        BlockData::from_data(
736            self._data.map(|d| ((d as i8) <= 0) as u8 as f64),
737            self._type,
738        )
739    }
740
741    pub fn gtz(&self) -> Self {
742        // Greater than zero
743        BlockData::from_data(self._data.map(|d| ((d as i8) > 0) as u8 as f64), self._type)
744    }
745
746    pub fn gtez(&self) -> Self {
747        // Greater than or equal to zero
748        BlockData::from_data(
749            self._data.map(|d| ((d as i8) >= 0) as u8 as f64),
750            self._type,
751        )
752    }
753
754    pub fn eqz(&self) -> Self {
755        // Equal to zero
756        BlockData::from_data(
757            self._data.map(|d| ((d as i8) == 0) as u8 as f64),
758            self._type,
759        )
760    }
761}
762
763pub trait FromPass<T: pictorus_traits::Pass> {
764    fn from_pass(pass: PassBy<T>) -> Self;
765}
766
767impl FromPass<f64> for BlockData {
768    fn from_pass(pass: f64) -> Self {
769        BlockData::from_scalar(pass)
770    }
771}
772
773impl FromPass<f32> for BlockData {
774    fn from_pass(pass: f32) -> Self {
775        BlockData::from_scalar(pass.into())
776    }
777}
778
779impl FromPass<u8> for BlockData {
780    fn from_pass(pass: u8) -> Self {
781        BlockData::from_scalar(pass.into())
782    }
783}
784
785impl FromPass<i8> for BlockData {
786    fn from_pass(pass: i8) -> Self {
787        BlockData::from_scalar(pass.into())
788    }
789}
790
791impl FromPass<u16> for BlockData {
792    fn from_pass(pass: u16) -> Self {
793        BlockData::from_scalar(pass.into())
794    }
795}
796
797impl FromPass<i16> for BlockData {
798    fn from_pass(pass: i16) -> Self {
799        BlockData::from_scalar(pass.into())
800    }
801}
802
803impl FromPass<u32> for BlockData {
804    fn from_pass(pass: u32) -> Self {
805        BlockData::from_scalar(pass.into())
806    }
807}
808
809impl FromPass<i32> for BlockData {
810    fn from_pass(pass: i32) -> Self {
811        BlockData::from_scalar(pass.into())
812    }
813}
814
815impl FromPass<bool> for BlockData {
816    fn from_pass(pass: PassBy<bool>) -> Self {
817        let scalar = if pass { 1. } else { 0. };
818        BlockData::from_scalar(scalar)
819    }
820}
821
822impl FromPass<ByteSliceSignal> for BlockData {
823    fn from_pass(pass: PassBy<ByteSliceSignal>) -> Self {
824        BlockData::from_bytes(pass)
825    }
826}
827
828impl<const NROWS: usize, const NCOLS: usize, T: pictorus_traits::Scalar>
829    FromPass<pictorus_traits::Matrix<NROWS, NCOLS, T>> for BlockData
830{
831    fn from_pass(pass: PassBy<pictorus_traits::Matrix<NROWS, NCOLS, T>>) -> Self {
832        let mut data = DMatrix::<f64>::zeros(NROWS, NCOLS);
833        for i in 0..NROWS {
834            for j in 0..NCOLS {
835                // Note the i,j <-> j,i here is not a bug but is due to Matrix storing data as `[[T; NROWS]; NCOLS]` so the first  `[]` indexes into the Columns
836                data[(i, j)] = pass.data[j][i].into();
837            }
838        }
839        BlockData::from_data(data, BlockDataType::Matrix)
840    }
841}
842
843pub trait ToPass<T: pictorus_traits::Pass> {
844    fn to_pass(&self) -> T;
845}
846
847impl ToPass<f64> for BlockData {
848    fn to_pass(&self) -> f64 {
849        self.scalar()
850    }
851}
852
853impl ToPass<bool> for BlockData {
854    fn to_pass(&self) -> bool {
855        self.scalar() != 0.0
856    }
857}
858
859impl<const N: usize> ToPass<[u8; N]> for BlockData {
860    fn to_pass(&self) -> [u8; N] {
861        let mut data = [0; N];
862        for (i, v) in self._data.iter().enumerate() {
863            data[i] = *v as u8;
864        }
865        data
866    }
867}
868
869impl<const N: usize> ToPass<[f64; N]> for BlockData {
870    fn to_pass(&self) -> [f64; N] {
871        let mut data = [0.0; N];
872        for (i, v) in self._data.iter().enumerate() {
873            data[i] = *v;
874        }
875        data
876    }
877}
878
879impl<const NROWS: usize, const NCOLS: usize> ToPass<pictorus_traits::Matrix<NROWS, NCOLS, f64>>
880    for BlockData
881{
882    fn to_pass(&self) -> pictorus_traits::Matrix<NROWS, NCOLS, f64> {
883        let mut data = pictorus_traits::Matrix::<NROWS, NCOLS, f64>::zeroed();
884        for i in 0..NROWS {
885            for j in 0..NCOLS {
886                // See the comment on `FromPass` for explanation of why indexes are switched
887                data.data[j][i] = self.at_rc(i, j);
888            }
889        }
890        data
891    }
892}
893
894impl<const NROWS: usize, const NCOLS: usize> ToPass<pictorus_traits::Matrix<NROWS, NCOLS, bool>>
895    for BlockData
896{
897    fn to_pass(&self) -> pictorus_traits::Matrix<NROWS, NCOLS, bool> {
898        let mut data = pictorus_traits::Matrix::<NROWS, NCOLS, bool>::zeroed();
899        for i in 0..NROWS {
900            for j in 0..NCOLS {
901                // See the comment on `FromPass` for explanation of why indexes are switched
902                data.data[j][i] = self.at_rc(i, j) != 0.0;
903            }
904        }
905        data
906    }
907}
908
909pub fn all_blocks_same_size(blocks: Vec<&BlockData>) -> bool {
910    for block in blocks.iter() {
911        if !block.same_size(blocks[0]) {
912            return false;
913        }
914    }
915    true
916}
917
918#[cfg(test)]
919#[allow(clippy::approx_constant)]
920mod tests {
921    use super::*;
922    use alloc::vec;
923    use approx::assert_relative_eq;
924    use pretty_assertions::assert_eq;
925
926    #[test]
927    fn test_array_constructor() {
928        let input = BlockData::new(2, 3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
929
930        assert_eq!(input.get_type(), BlockDataType::Matrix);
931        assert_eq!(
932            input._data.row(0),
933            DMatrix::<f64>::from_row_slice(1, 3, &[1.0, 2.0, 3.0])
934        );
935        assert_eq!(
936            input._data.row(1),
937            DMatrix::<f64>::from_row_slice(1, 3, &[4.0, 5.0, 6.0])
938        );
939    }
940
941    #[test]
942    fn test_scalar_constructor() {
943        let input = BlockData::from_scalar(3.14159);
944
945        assert_eq!(input.get_type(), BlockDataType::Scalar);
946        assert_eq!(input.scalar(), 3.14159);
947    }
948
949    #[test]
950    fn test_set_scalar() {
951        let mut input = BlockData::from_scalar(3.14159);
952        input.set_scalar(1.0);
953
954        assert_eq!(input.get_type(), BlockDataType::Scalar);
955        assert_eq!(input.scalar(), 1.0);
956    }
957
958    #[test]
959    fn test_bool_constructor() {
960        let block = BlockData::scalar_from_bool(false);
961        assert!(!block.any());
962
963        let block = BlockData::scalar_from_bool(true);
964        assert!(block.all())
965    }
966
967    #[test]
968    fn test_vector_constructor() {
969        let block = BlockData::from_matrix(&[&[1., 2.], &[3., 4.], &[5., 6.]]);
970
971        assert!(block.get_type() == BlockDataType::Matrix);
972        assert!(block.nrows() == 3);
973        assert!(block.ncols() == 2);
974        assert!(block.at_rc(0, 0) == 1.);
975        assert!(block.at_rc(0, 1) == 2.);
976        assert!(block.at_rc(1, 0) == 3.);
977        assert!(block.at_rc(1, 1) == 4.);
978        assert!(block.at_rc(2, 0) == 5.);
979        assert!(block.at_rc(2, 1) == 6.);
980    }
981
982    #[test]
983    fn test_set_bool() {
984        let mut block = BlockData::scalar_from_bool(false);
985
986        block.set_scalar_bool(true);
987        assert!(block.all());
988
989        block.set_scalar_bool(false);
990        assert!(!block.any());
991    }
992
993    #[test]
994    fn test_or() {
995        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
996        let b = BlockData::zeros_sizeof(&a);
997
998        assert_eq!(a.or(&b), BlockData::from_vector(&[1.0, 0.0, 1.0, 1.0]));
999    }
1000
1001    #[test]
1002    fn test_and() {
1003        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1004        let b = BlockData::from_vector(&[0., 0., 1., -2.]);
1005
1006        assert_eq!(a.and(&b), BlockData::from_vector(&[0.0, 0.0, 1.0, 1.0]));
1007    }
1008
1009    #[test]
1010    fn test_eq() {
1011        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1012        let b = BlockData::zeros_sizeof(&a);
1013
1014        assert_eq!(a.eq(&b), BlockData::from_vector(&[0.0, 1.0, 0.0, 0.0]));
1015    }
1016
1017    #[test]
1018    fn test_neq() {
1019        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1020        let b = BlockData::zeros_sizeof(&a);
1021
1022        assert_eq!(a.neq(&b), BlockData::from_vector(&[1.0, 0.0, 1.0, 1.0]));
1023    }
1024
1025    #[test]
1026    fn test_gt() {
1027        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1028        let b = BlockData::zeros_sizeof(&a);
1029
1030        assert_eq!(a.gt(&b), BlockData::from_vector(&[0.0, 0.0, 1.0, 1.0]));
1031    }
1032
1033    #[test]
1034    fn test_gte() {
1035        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1036        let b = BlockData::zeros_sizeof(&a);
1037
1038        assert_eq!(a.gte(&b), BlockData::from_vector(&[0.0, 1.0, 1.0, 1.0]));
1039    }
1040
1041    #[test]
1042    fn test_lt() {
1043        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1044        let b = BlockData::zeros_sizeof(&a);
1045
1046        assert_eq!(a.lt(&b), BlockData::from_vector(&[1.0, 0.0, 0.0, 0.0]));
1047    }
1048
1049    #[test]
1050    fn test_lte() {
1051        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1052        let b = BlockData::zeros_sizeof(&a);
1053
1054        assert_eq!(a.lte(&b), BlockData::from_vector(&[1.0, 1.0, 0.0, 0.0]));
1055    }
1056
1057    #[test]
1058    fn test_ltz() {
1059        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1060        assert_eq!(a.ltz(), BlockData::from_vector(&[1.0, 0.0, 0.0, 0.0]));
1061    }
1062
1063    #[test]
1064    fn test_gtz() {
1065        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1066        assert_eq!(a.gtz(), BlockData::from_vector(&[0.0, 0.0, 1.0, 1.0]));
1067    }
1068
1069    #[test]
1070    fn test_ltez() {
1071        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1072        assert_eq!(a.ltez(), BlockData::from_vector(&[1.0, 1.0, 0.0, 0.0]));
1073    }
1074
1075    #[test]
1076    fn test_gtez() {
1077        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1078        assert_eq!(a.gtez(), BlockData::from_vector(&[0.0, 1.0, 1.0, 1.0]));
1079    }
1080
1081    #[test]
1082    fn test_not() {
1083        let a = BlockData::from_vector(&[-1., 0., 1., 2.]);
1084        assert_eq!(
1085            a.logical_not(),
1086            BlockData::from_vector(&[0.0, 1.0, 0.0, 0.0])
1087        );
1088    }
1089
1090    #[test]
1091    fn test_maybe_reset() {
1092        let mut a = BlockData::from_vector(&[-1., 10., 20., 2.]);
1093        a.maybe_reset(&BlockData::from_vector(&[-1., 0., 1., 2.]));
1094
1095        assert_eq!(a, BlockData::from_vector(&[0.0, 10.0, 0.0, 0.0]));
1096
1097        // Can also reset a matrix with a scalar reset
1098        a.maybe_reset(&BlockData::from_scalar(1.0));
1099        assert_eq!(a, BlockData::from_vector(&[0.0, 0.0, 0.0, 0.0]));
1100    }
1101
1102    #[test]
1103    fn test_powf() {
1104        let base = BlockData::from_vector(&[1.0, -2.0, 3.0]);
1105        let exponent = BlockData::from_vector(&[2.0, 3.0, 4.0]);
1106
1107        assert_eq!(
1108            base.powf(&exponent),
1109            BlockData::from_vector(&[1.0, -8.0, 81.0])
1110        );
1111    }
1112
1113    #[test]
1114    fn test_sign() {
1115        assert_eq!(
1116            BlockData::from_vector(&[-2., -1., 0., 1., 2.]).sign(),
1117            BlockData::from_vector(&[-1., -1., 0., 1., 1.]),
1118        );
1119    }
1120
1121    #[test]
1122    fn test_boolean() {
1123        assert_eq!(
1124            BlockData::from_vector(&[-2., -1., 0., 1., 2.]).boolean(),
1125            BlockData::from_vector(&[1., 1., 0., 1., 1.]),
1126        );
1127    }
1128
1129    #[test]
1130    fn test_all() {
1131        assert_eq!(BlockData::from_vector(&[-2., -1., 0., 1., 2.]).all(), false);
1132        assert_eq!(BlockData::from_vector(&[-2., -1., 1., 1., 2.]).all(), true);
1133    }
1134    #[test]
1135    fn test_any() {
1136        assert_eq!(BlockData::from_vector(&[-2., -1., 0., 1., 2.]).any(), true);
1137        assert_eq!(BlockData::from_vector(&[0., 0., 0., 0., 0.]).any(), false);
1138    }
1139    #[test]
1140    fn test_inverse() {
1141        let block = BlockData::new(2, 2, &[1., 2., 3., 4.]);
1142        // From numpy
1143        assert_eq!(
1144            block.inverse().unwrap(),
1145            BlockData::new(2, 2, &[-2., 1., 1.5, -0.5])
1146        );
1147    }
1148    #[test]
1149    fn test_dot() {
1150        let block1 = BlockData::new(1, 3, &[1.0, 2.0, 3.0]);
1151        let block2 = BlockData::new(1, 3, &[4.0, 1.0, 0.0]);
1152        // From numpy
1153        assert_eq!(block1.dot(&block2), BlockData::from_scalar(6.0));
1154    }
1155    #[test]
1156    fn test_determinant() {
1157        let block = BlockData::new(2, 2, &[1.0, 2.0, 3.0, 4.0]);
1158        // From numpy
1159        assert_eq!(block.determinant(), BlockData::from_scalar(-2.0));
1160    }
1161    #[test]
1162    fn test_cross() {
1163        let block1 = BlockData::new(1, 3, &[1.0, 0.0, 0.0]);
1164        let block2 = BlockData::new(1, 3, &[0.0, 1.0, 0.0]);
1165        // From numpy
1166        assert_eq!(
1167            block1.cross(&block2),
1168            BlockData::new(1, 3, &[0.0, 0.0, 1.0])
1169        );
1170    }
1171    #[test]
1172    fn test_transpose() {
1173        let block = BlockData::new(3, 2, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1174        // From numpy
1175        assert_eq!(
1176            block.transpose(),
1177            BlockData::new(2, 3, &[1.0, 3.0, 5.0, 2.0, 4.0, 6.0])
1178        );
1179    }
1180    #[test]
1181    fn test_sum() {
1182        let block = BlockData::new(3, 2, &[1.0, 2.0, 3.0, 4.0, 5.0, -6.0]);
1183        assert_eq!(block.sum(), 9.0);
1184    }
1185    #[test]
1186    fn test_mean() {
1187        let block = BlockData::new(3, 2, &[1.0, 2.0, 3.0, 4.0, 5.0, -6.0]);
1188        assert_eq!(block.mean(), 1.5);
1189    }
1190    #[test]
1191    fn test_median() {
1192        assert_eq!(
1193            BlockData::new(1, 7, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]).median(),
1194            4.0
1195        );
1196        assert_eq!(
1197            BlockData::new(1, 6, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).median(),
1198            3.5
1199        );
1200    }
1201    #[test]
1202    fn test_min() {
1203        assert_eq!(
1204            BlockData::new(1, 7, &[1.0, 2.0, 3.0, 4.0, -5.0, 6.0, 7.0]).min(),
1205            -5.0
1206        );
1207    }
1208    #[test]
1209    fn test_max() {
1210        assert_eq!(
1211            BlockData::new(1, 7, &[1.0, 2.0, 3.0, 4.0, -5.0, 6.0, 7.0]).max(),
1212            7.0
1213        );
1214    }
1215    #[test]
1216    fn test_component_div() {
1217        // Divide scalar by vector
1218        assert_eq!(
1219            BlockData::from_scalar(1.0) / BlockData::new(1, 2, &[2.0, -4.0]),
1220            BlockData::new(1, 2, &[0.5, -0.25])
1221        );
1222        // Divide vector by scalar
1223        assert_eq!(
1224            BlockData::new(1, 2, &[2.0, -4.0]) / BlockData::from_scalar(2.0),
1225            BlockData::new(1, 2, &[1.0, -2.0])
1226        );
1227        // Divide vector by vector
1228        assert_eq!(
1229            BlockData::new(1, 2, &[2.0, -4.0]) / BlockData::new(1, 2, &[4.0, -0.5]),
1230            BlockData::new(1, 2, &[0.5, 8.0])
1231        );
1232    }
1233    #[test]
1234    fn test_component_mul() {
1235        // scalar by vector
1236        assert_eq!(
1237            BlockData::from_scalar(2.0).component_mul(&BlockData::new(1, 2, &[2.0, -4.0])),
1238            BlockData::new(1, 2, &[4.0, -8.0])
1239        );
1240        // flip order
1241        assert_eq!(
1242            BlockData::new(1, 2, &[2.0, -4.0]).component_mul(&BlockData::from_scalar(2.0)),
1243            BlockData::new(1, 2, &[4.0, -8.0])
1244        );
1245        // vector by scalar
1246        assert_eq!(
1247            BlockData::new(1, 2, &[2.0, -4.0]).component_mul(&BlockData::from_scalar(2.0)),
1248            BlockData::new(1, 2, &[4.0, -8.0])
1249        );
1250        // vector by vector
1251        assert_eq!(
1252            BlockData::new(1, 2, &[2.0, -4.0]).component_mul(&BlockData::new(1, 2, &[4.0, -0.5])),
1253            BlockData::new(1, 2, &[8.0, 2.0])
1254        );
1255    }
1256    #[test]
1257    fn test_component_add() {
1258        // scalar by vector
1259        assert_eq!(
1260            BlockData::from_scalar(2.0) + &BlockData::new(1, 2, &[2.0, -4.0]),
1261            BlockData::new(1, 2, &[4.0, -2.0])
1262        );
1263        // vector by scalar
1264        assert_eq!(
1265            BlockData::new(1, 2, &[2.0, -4.0]) + &BlockData::from_scalar(2.0),
1266            BlockData::new(1, 2, &[4.0, -2.0])
1267        );
1268        // vector by vector
1269        assert_eq!(
1270            BlockData::new(1, 2, &[2.0, -4.0]) + &BlockData::new(1, 2, &[4.0, -0.5]),
1271            BlockData::new(1, 2, &[6.0, -4.5])
1272        );
1273        // vector by scalar, in place
1274        let mut b = BlockData::new(1, 2, &[2.0, -4.0]);
1275        b += &BlockData::from_scalar(2.0);
1276        assert_eq!(b, BlockData::new(1, 2, &[4.0, -2.0]));
1277    }
1278    #[test]
1279    fn test_component_sub() {
1280        // scalar by vector
1281        assert_eq!(
1282            BlockData::from_scalar(2.0) - &BlockData::new(1, 2, &[2.0, -4.0]),
1283            BlockData::new(1, 2, &[0.0, 6.0])
1284        );
1285        // vector by scalar
1286        assert_eq!(
1287            BlockData::new(1, 2, &[2.0, -4.0]) - &BlockData::from_scalar(2.0),
1288            BlockData::new(1, 2, &[0.0, -6.0])
1289        );
1290        // vector by vector
1291        assert_eq!(
1292            BlockData::new(1, 2, &[2.0, -4.0]) - &BlockData::new(1, 2, &[4.0, -0.5]),
1293            BlockData::new(1, 2, &[-2.0, -3.5])
1294        );
1295        // vector by scalar, in place
1296        let mut b = BlockData::new(1, 2, &[2.0, -4.0]);
1297        b -= &BlockData::from_scalar(2.0);
1298        assert_eq!(b, BlockData::new(1, 2, &[0.0, -6.0]));
1299    }
1300
1301    #[test]
1302    fn test_component_bitnot() {
1303        // Test data with positive and negative numbers
1304        let block = BlockData::from_vector(&[42.0, -3.5, 0.0, -1.0]);
1305        let expected = BlockData::from_vector(&[-43.0, 2.0, -1.0, 0.0]);
1306
1307        // Test the function with the test data
1308        assert_eq!(block.component_bitnot(), expected);
1309    }
1310
1311    #[test]
1312    fn test_bitand() {
1313        let a = BlockData::from_vector(&[1., 2., 3.]);
1314        let b = BlockData::from_vector(&[1., 1., 2.]);
1315        let c = a & b;
1316
1317        let expected = BlockData::from_vector(&[1.0, 0.0, 2.0]);
1318        assert_eq!(c, expected);
1319    }
1320
1321    #[test]
1322    fn test_bitor() {
1323        let a = BlockData::from_vector(&[1., 2., 3.]);
1324        let b = BlockData::from_vector(&[2., 3., 3.]);
1325        let c = a | b;
1326
1327        let expected = BlockData::from_vector(&[3.0, 3.0, 3.0]);
1328        assert_eq!(c, expected);
1329    }
1330
1331    #[test]
1332    fn test_bitxor() {
1333        let a = BlockData::from_vector(&[1., 2., 3.]);
1334        let b = BlockData::from_vector(&[2., 1., 0.]);
1335        let c = a ^ b;
1336
1337        let expected = BlockData::from_vector(&[3.0, 3.0, 3.0]);
1338        assert_eq!(c, expected);
1339    }
1340
1341    #[test]
1342    fn test_shl() {
1343        let data = BlockData::from_vector(&[1., 2., 3.]);
1344        let shifted = data << 1;
1345
1346        let expected = BlockData::from_vector(&[2.0, 4.0, 6.0]);
1347        assert_eq!(shifted, expected);
1348    }
1349
1350    #[test]
1351    fn test_shr() {
1352        let data = BlockData::from_vector(&[1., 2., 4.]);
1353        let shifted = data >> 1;
1354
1355        let expected = BlockData::from_vector(&[0.0, 1.0, 2.0]);
1356        assert_eq!(shifted, expected);
1357    }
1358
1359    #[test]
1360    fn test_fix_non_finite() {
1361        let mut data = BlockData::from_row_slice(
1362            1,
1363            6,
1364            &[1.0, f64::NAN, f64::INFINITY, f64::NEG_INFINITY, 5.0, 6.0],
1365        );
1366
1367        data.fix_non_finite();
1368
1369        assert_eq!(
1370            data,
1371            BlockData::from_row_slice(1, 6, &[1.0, 0.0, 0.0, 0.0, 5.0, 6.0])
1372        );
1373    }
1374
1375    #[test]
1376    fn test_vector_magnitude() {
1377        let data = BlockData::from_matrix(&[&[0., 1., 2.], &[3., 4., 5.], &[6., 7., 8.]]);
1378
1379        assert_relative_eq!(
1380            data.vector_magnitude(),
1381            BlockData::from_row_slice(1, 3, &[6.7, 8.1, 9.6]),
1382            max_relative = 0.1
1383        );
1384
1385        assert_relative_eq!(
1386            data.vector_magnitude_rows(),
1387            BlockData::from_row_slice(1, 3, &[2.2, 7.1, 12.2]),
1388            max_relative = 0.1
1389        );
1390    }
1391
1392    #[test]
1393    fn test_stringify() {
1394        let scalar_data = BlockData::from_scalar(3.14159);
1395        let arr_data = BlockData::from_vector(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1396        let matrix_data = BlockData::from_row_slice(3, 2, &[1., 2., 3., 4., 5., 6.]);
1397        let bytes_data = BlockData::from_bytes(&[1, 2, 3, 4, 5, 6]);
1398        let str_data = BlockData::from_bytes(b"Hello, world!");
1399
1400        assert_eq!(scalar_data.stringify(), "3.14159");
1401        assert_eq!(arr_data.stringify(), "[[1.0,2.0,3.0,4.0,5.0,6.0]]");
1402        assert_eq!(matrix_data.stringify(), "[[1.0,2.0],[3.0,4.0],[5.0,6.0]]");
1403        assert_eq!(bytes_data.stringify(), "[1,2,3,4,5,6]");
1404        assert_eq!(
1405            str_data.stringify(),
1406            "[72,101,108,108,111,44,32,119,111,114,108,100,33]"
1407        );
1408    }
1409
1410    #[test]
1411    fn test_raw_string() {
1412        let scalar_data = BlockData::from_scalar(3.14159);
1413        let arr_data = BlockData::from_vector(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1414        let matrix_data = BlockData::from_row_slice(3, 2, &[1., 2., 3., 4., 5., 6.]);
1415
1416        let non_std_bytes = vec![1, 2, 3, 4, 5, 6];
1417        let bytes_data = BlockData::from_bytes(&non_std_bytes);
1418        let str_data = BlockData::from_bytes(b"Hello, world!");
1419
1420        assert_eq!(scalar_data.raw_string(), "3.14159");
1421        assert_eq!(arr_data.raw_string(), "[[1.0,2.0,3.0,4.0,5.0,6.0]]");
1422        assert_eq!(matrix_data.raw_string(), "[[1.0,2.0],[3.0,4.0],[5.0,6.0]]");
1423        assert_eq!(
1424            bytes_data.raw_string(),
1425            String::from_utf8(non_std_bytes).unwrap()
1426        );
1427        assert_eq!(str_data.raw_string(), "Hello, world!");
1428    }
1429
1430    #[test]
1431    fn test_argmax() {
1432        let data = BlockData::from_vector(&[3.0, 1.0, 2.0, 4.0, 5.0]);
1433        assert_eq!(data.argmax(), 4.0);
1434
1435        // | 3 1 2 |
1436        // | 6 5 4 |  linear index of the max is "1.0"
1437        let data_matrix = BlockData::from_row_slice(2, 3, &[3.0, 1.0, 2.0, 6.0, 5.0, 4.0]);
1438        assert_eq!(data_matrix.argmax(), 1.0);
1439    }
1440
1441    #[test]
1442    fn test_argmin() {
1443        let data = BlockData::from_vector(&[3.0, 1.0, 2.0, 4.0, 5.0]);
1444        assert_eq!(data.argmin(), 1.0);
1445
1446        let data_matrix = BlockData::from_row_slice(2, 3, &[3.0, 1.0, 2.0, 4.0, 5.0, 6.0]);
1447        assert_eq!(data_matrix.argmin(), 2.0);
1448    }
1449
1450    #[test]
1451    fn test_block_data_scalar_read_write_traits() {
1452        let mut data = BlockData::from_scalar(1.0);
1453        {
1454            let data_read = &data;
1455            assert_eq!(data_read.get_scalar(), 1.0);
1456        }
1457
1458        {
1459            let mut data_write = &mut data;
1460            data_write.set_scalar_value(2.0);
1461        }
1462        assert_eq!(data.get_type(), BlockDataType::Scalar);
1463
1464        {
1465            let data_read = &data;
1466            assert_eq!(data_read.get_scalar(), 2.0);
1467        }
1468    }
1469
1470    #[test]
1471    fn test_block_data_matrix_read_write_traits() {
1472        let nrows = 1;
1473        let ncols = 3;
1474        let slice_data = [1.0, 2.0, 3.0];
1475        let mut data = BlockData::from_row_slice(nrows, ncols, &slice_data);
1476        let data_read = &data;
1477        {
1478            assert_eq!(
1479                data_read.get_matrix(),
1480                (nrows, ncols, slice_data.as_slice())
1481            );
1482        }
1483
1484        let nrows = 2;
1485        let ncols = 2;
1486        let slice_data = [4.0, 6.0, 5.0, 7.0];
1487        {
1488            let mut data_write = &mut data;
1489            data_write.set_matrix_value(nrows, ncols, slice_data.as_slice());
1490        }
1491        assert_eq!(data.get_type(), BlockDataType::Matrix);
1492
1493        {
1494            let data_read = &data;
1495            let (nrows, ncols, _read_slice) = data_read.get_matrix();
1496            assert_eq!(
1497                data_read.get_matrix(),
1498                (nrows, ncols, slice_data.as_slice())
1499            );
1500        }
1501    }
1502
1503    #[test]
1504    fn test_sorted() {
1505        let data = BlockData::from_vector(&[3.0, 1.0, 2.0, 4.0, 5.0]);
1506        let sorted = data.sorted(true);
1507        assert_eq!(sorted, BlockData::from_vector(&[1.0, 2.0, 3.0, 4.0, 5.0]));
1508
1509        let sorted = data.sorted(false);
1510        assert_eq!(sorted, BlockData::from_vector(&[5.0, 4.0, 3.0, 2.0, 1.0]));
1511
1512        let data_matrix = BlockData::from_row_slice(2, 3, &[3.0, 1.0, 2.0, 4.0, 5.0, 6.0]);
1513        let sorted = data_matrix.sorted(true);
1514        assert_eq!(
1515            sorted,
1516            BlockData::from_vector(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
1517        );
1518    }
1519}