scirs2_core/ndarray/
mod.rs

1//! Complete ndarray re-export for SciRS2 ecosystem
2//!
3//! This module provides a single, unified access point for ALL ndarray functionality,
4//! ensuring SciRS2 POLICY compliance across the entire ecosystem.
5//!
6//! ## Design Philosophy
7//!
8//! 1. **Complete Feature Parity**: All ndarray functionality available through scirs2-core
9//! 2. **Zero Breaking Changes**: Existing ndarray_ext continues to work
10//! 3. **Policy Compliance**: No need for direct ndarray imports anywhere
11//! 4. **Single Source of Truth**: One place for all array operations
12//!
13//! ## Usage
14//!
15//! ```rust
16//! // Instead of:
17//! use ndarray::{Array, array, s, Axis};  // ❌ POLICY violation
18//!
19//! // Use:
20//! use scirs2_core::ndarray::*;  // ✅ POLICY compliant
21//!
22//! let arr = array![[1, 2], [3, 4]];
23//! let slice = arr.slice(s![.., 0]);
24//! ```
25
26// ========================================
27// COMPLETE NDARRAY RE-EXPORT
28// ========================================
29
30/// Re-export everything from ndarray crate
31pub use ndarray::*;
32
33// Ensure specific items are definitely available (for clarity)
34pub use ndarray::{
35    ArcArray,
36    ArcArray1,
37    ArcArray2,
38    // Core array types
39    Array,
40    Array0,
41    Array1,
42    Array2,
43    Array3,
44    Array4,
45    Array5,
46    Array6,
47    ArrayBase,
48    // Builder patterns
49    ArrayBase as NdArray,
50
51    ArrayD,
52    // View types
53    ArrayView,
54    ArrayView0,
55    ArrayView1,
56    ArrayView2,
57    ArrayView3,
58    ArrayView4,
59    ArrayView5,
60    ArrayView6,
61    ArrayViewD,
62    ArrayViewMut,
63    ArrayViewMut0,
64    ArrayViewMut1,
65    ArrayViewMut2,
66    ArrayViewMut3,
67    ArrayViewMut4,
68    ArrayViewMut5,
69    ArrayViewMut6,
70    ArrayViewMutD,
71
72    AsArray,
73
74    // Axis and indexing
75    Axis,
76    AxisDescription,
77    CowArray,
78    // Essential traits
79    Data,
80    DataMut,
81    DataOwned,
82    DataShared,
83    // Dimension types
84    Dim,
85    Dimension,
86    // Utility types
87    ErrorKind,
88    FoldWhile,
89
90    Ix0,
91    Ix1,
92    Ix2,
93    Ix3,
94    Ix4,
95    Ix5,
96    Ix6,
97    IxDyn,
98    IxDynImpl,
99    // Mathematical operations
100    LinalgScalar,
101    NdFloat,
102
103    NdProducer,
104    NewAxis,
105
106    Order,
107    OwnedArcRepr,
108    // Storage
109    OwnedRepr,
110    RawArrayView,
111    RawArrayViewMut,
112
113    RawData,
114    RawDataClone,
115    RawDataMut,
116    RawViewRepr,
117
118    RemoveAxis,
119
120    ScalarOperand,
121    // Shape and strides
122    Shape,
123    ShapeBuilder,
124    ShapeError,
125
126    Slice,
127    SliceArg,
128    SliceInfo,
129    SliceInfoElem,
130    StrideShape,
131    ViewRepr,
132    // Iteration
133    Zip,
134};
135
136// ========================================
137// ESSENTIAL MACROS
138// ========================================
139
140/// Re-export essential macros that were missing in some modules
141pub use ndarray::{
142    arr0, // Creates 0-dimensional arrays
143    arr1, // Creates 1-dimensional arrays
144    arr2, // Creates 2-dimensional arrays
145    arr3, // Creates 3-dimensional arrays
146    // Array creation macros
147    array, // Creates arrays with literal syntax
148    azip,  // Zip iterator macro
149    s,     // Slicing macro - CRITICAL for ToRSh
150    stack, // Stack arrays macro
151};
152
153// ========================================
154// NDARRAY-RELATED CRATE RE-EXPORTS
155// ========================================
156
157#[cfg(feature = "random")]
158pub use ndarray_rand::{rand_distr as distributions, RandomExt, SamplingStrategy};
159
160#[cfg(feature = "linalg")]
161pub use ndarray_linalg;
162
163#[cfg(feature = "array_stats")]
164pub use ndarray_stats::{
165    errors as stats_errors, interpolate, CorrelationExt, DeviationExt, MaybeNan, QuantileExt,
166    Sort1dExt, SummaryStatisticsExt,
167};
168
169#[cfg(feature = "array_io")]
170pub use ndarray_npy::{
171    NpzReader, NpzWriter, ReadNpyExt, ReadNpzError, ViewMutNpyExt, ViewNpyExt, WriteNpyError,
172    WriteNpyExt,
173};
174
175// ========================================
176// ENHANCED FUNCTIONALITY
177// ========================================
178
179/// Additional utilities for SciRS2 ecosystem
180pub mod utils {
181    use super::*;
182
183    /// Create an identity matrix
184    pub fn eye<A>(n: usize) -> Array2<A>
185    where
186        A: Clone + num_traits::Zero + num_traits::One,
187    {
188        let mut arr = Array2::zeros((n, n));
189        for i in 0..n {
190            arr[[i, i]] = A::one();
191        }
192        arr
193    }
194
195    /// Create a diagonal matrix from a vector
196    pub fn diag<A>(v: &Array1<A>) -> Array2<A>
197    where
198        A: Clone + num_traits::Zero,
199    {
200        let n = v.len();
201        let mut arr = Array2::zeros((n, n));
202        for i in 0..n {
203            arr[[i, i]] = v[i].clone();
204        }
205        arr
206    }
207
208    /// Check if arrays are approximately equal
209    pub fn allclose<A, D>(
210        a: &ArrayBase<impl Data<Elem = A>, D>,
211        b: &ArrayBase<impl Data<Elem = A>, D>,
212        rtol: A,
213        atol: A,
214    ) -> bool
215    where
216        A: PartialOrd
217            + std::ops::Sub<Output = A>
218            + std::ops::Mul<Output = A>
219            + std::ops::Add<Output = A>
220            + Clone,
221        D: Dimension,
222    {
223        if a.shape() != b.shape() {
224            return false;
225        }
226
227        a.iter().zip(b.iter()).all(|(a_val, b_val)| {
228            let diff = if a_val > b_val {
229                a_val.clone() - b_val.clone()
230            } else {
231                b_val.clone() - a_val.clone()
232            };
233
234            let threshold = atol.clone()
235                + rtol.clone()
236                    * (if a_val > b_val {
237                        a_val.clone()
238                    } else {
239                        b_val.clone()
240                    });
241
242            diff <= threshold
243        })
244    }
245
246    /// Concatenate arrays along an axis
247    pub fn concatenate<A, D>(
248        axis: Axis,
249        arrays: &[ArrayView<A, D>],
250    ) -> Result<Array<A, D>, ShapeError>
251    where
252        A: Clone,
253        D: Dimension + RemoveAxis,
254    {
255        ndarray::concatenate(axis, arrays)
256    }
257
258    /// Stack arrays along a new axis
259    pub fn stack<A, D>(
260        axis: Axis,
261        arrays: &[ArrayView<A, D>],
262    ) -> Result<Array<A, D::Larger>, ShapeError>
263    where
264        A: Clone,
265        D: Dimension,
266        D::Larger: RemoveAxis,
267    {
268        ndarray::stack(axis, arrays)
269    }
270}
271
272// ========================================
273// COMPATIBILITY LAYER
274// ========================================
275
276/// Compatibility module for smooth migration from fragmented imports
277pub mod compat {
278    pub use super::*;
279
280    /// Alias for commonly used types to match existing usage patterns
281    pub type DynArray<T> = ArrayD<T>;
282    pub type Matrix<T> = Array2<T>;
283    pub type Vector<T> = Array1<T>;
284    pub type Tensor3<T> = Array3<T>;
285    pub type Tensor4<T> = Array4<T>;
286
287    /// Re-export from ndarray_ext for backward compatibility
288    pub use crate::ndarray_ext::{
289        broadcast_1d_to_2d,
290        broadcast_apply,
291        fancy_index_2d,
292        // Keep existing extended functionality
293        indexing,
294        is_broadcast_compatible,
295        manipulation,
296        mask_select,
297        matrix,
298        reshape_2d,
299        split_2d,
300        stack_2d,
301        stats,
302        take_2d,
303        transpose_2d,
304        where_condition,
305    };
306}
307
308// ========================================
309// PRELUDE MODULE
310// ========================================
311
312/// Prelude module with most commonly used items
313pub mod prelude {
314    pub use super::{
315        arr1,
316        arr2,
317        // Essential macros
318        array,
319        azip,
320        // Utilities
321        concatenate,
322        s,
323        stack,
324
325        stack as stack_fn,
326        // Essential types
327        Array,
328        Array0,
329        Array1,
330        Array2,
331        Array3,
332        ArrayD,
333        ArrayView,
334        ArrayView1,
335        ArrayView2,
336        ArrayViewMut,
337
338        // Common operations
339        Axis,
340        // Essential traits
341        Dimension,
342        Ix1,
343        Ix2,
344        Ix3,
345        IxDyn,
346        ScalarOperand,
347        ShapeBuilder,
348
349        Zip,
350    };
351
352    #[cfg(feature = "random")]
353    pub use super::RandomExt;
354
355    // Useful type aliases
356    pub type Matrix<T> = super::Array2<T>;
357    pub type Vector<T> = super::Array1<T>;
358}
359
360// ========================================
361// EXAMPLES MODULE
362// ========================================
363
364#[cfg(test)]
365pub mod examples {
366    //! Examples demonstrating unified ndarray access through scirs2-core
367
368    use super::*;
369
370    /// Example: Using all essential ndarray features through scirs2-core
371    ///
372    /// ```
373    /// use scirs2_core::ndarray::*;
374    ///
375    /// // Create arrays using the array! macro
376    /// let a = array![[1, 2, 3], [4, 5, 6]];
377    ///
378    /// // Use the s! macro for slicing
379    /// let row = a.slice(s![0, ..]);
380    /// let col = a.slice(s![.., 1]);
381    ///
382    /// // Use Axis for operations
383    /// let sum_axis0 = a.sum_axis(Axis(0));
384    /// let mean_axis1 = a.mean_axis(Axis(1));
385    ///
386    /// // Stack and concatenate
387    /// let b = array![[7, 8, 9], [10, 11, 12]];
388    /// let stacked = stack![Axis(0), a, b];
389    ///
390    /// // Views and iteration
391    /// for row in a.axis_iter(Axis(0)) {
392    ///     println!("Row: {:?}", row);
393    /// }
394    /// ```
395    #[test]
396    fn test_complete_functionality() {
397        // Array creation
398        let a = array![[1., 2.], [3., 4.]];
399        assert_eq!(a.shape(), &[2, 2]);
400
401        // Slicing with s! macro
402        let slice = a.slice(s![.., 0]);
403        assert_eq!(slice.len(), 2);
404
405        // Mathematical operations
406        let b = &a + &a;
407        assert_eq!(b[[0, 0]], 2.);
408
409        // Axis operations
410        let sum = a.sum_axis(Axis(0));
411        assert_eq!(sum.len(), 2);
412
413        // Broadcasting
414        let c = array![1., 2.];
415        let d = &a + &c;
416        assert_eq!(d[[0, 0]], 2.);
417    }
418}
419
420// ========================================
421// MIGRATION GUIDE
422// ========================================
423
424pub mod migration_guide {
425    //! # Migration Guide: From Fragmented to Unified ndarray Access
426    //!
427    //! ## Before (Fragmented, Policy-Violating)
428    //!
429    //! ```rust,ignore
430    //! // Different files used different imports
431    //! use scirs2_autograd::ndarray::{Array1, array};
432    //! use scirs2_core::ndarray_ext::{ArrayView};
433    //! use ndarray::{s!, Axis};  // POLICY VIOLATION!
434    //! ```
435    //!
436    //! ## After (Unified, Policy-Compliant)
437    //!
438    //! ```rust,ignore
439    //! // Single, consistent import
440    //! use scirs2_core::ndarray::*;
441    //!
442    //! // Everything works:
443    //! let arr = array![[1, 2], [3, 4]];
444    //! let slice = arr.slice(s![.., 0]);
445    //! let view: ArrayView<_, _> = arr.view();
446    //! let sum = arr.sum_axis(Axis(0));
447    //! ```
448    //!
449    //! ## Benefits
450    //!
451    //! 1. **Single Import Path**: No more confusion about where to import from
452    //! 2. **Complete Functionality**: All ndarray features available
453    //! 3. **Policy Compliance**: No direct ndarray imports needed
454    //! 4. **Future-Proof**: Centralized control over array functionality
455    //!
456    //! ## Quick Reference
457    //!
458    //! | Old Import | New Import |
459    //! |------------|------------|
460    //! | `use ndarray::{Array, array}` | `use scirs2_core::ndarray::{Array, array}` |
461    //! | `use scirs2_autograd::ndarray::*` | `use scirs2_core::ndarray::*` |
462    //! | `use scirs2_core::ndarray_ext::*` | `use scirs2_core::ndarray::*` |
463    //! | `use ndarray::{s!, Axis}` | `use scirs2_core::ndarray::{s, Axis}` |
464}
465
466#[cfg(test)]
467mod tests {
468    use super::*;
469
470    #[test]
471    fn test_array_macro_available() {
472        let arr = array![[1, 2], [3, 4]];
473        assert_eq!(arr.shape(), &[2, 2]);
474        assert_eq!(arr[[0, 0]], 1);
475    }
476
477    #[test]
478    fn test_s_macro_available() {
479        let arr = array![[1, 2, 3], [4, 5, 6]];
480        let slice = arr.slice(s![.., 1..]);
481        assert_eq!(slice.shape(), &[2, 2]);
482    }
483
484    #[test]
485    fn test_axis_operations() {
486        let arr = array![[1., 2.], [3., 4.]];
487        let sum = arr.sum_axis(Axis(0));
488        assert_eq!(sum, array![4., 6.]);
489    }
490
491    #[test]
492    fn test_views_and_iteration() {
493        let mut arr = array![[1, 2], [3, 4]];
494
495        // Test immutable view first
496        {
497            let view: ArrayView<_, _> = arr.view();
498            for val in view.iter() {
499                assert!(*val > 0);
500            }
501        }
502
503        // Test mutable view after immutable view is dropped
504        {
505            let mut view_mut: ArrayViewMut<_, _> = arr.view_mut();
506            for val in view_mut.iter_mut() {
507                *val *= 2;
508            }
509        }
510
511        assert_eq!(arr[[0, 0]], 2);
512    }
513
514    #[test]
515    fn test_concatenate_and_stack() {
516        let a = array![[1, 2], [3, 4]];
517        let b = array![[5, 6], [7, 8]];
518
519        // Concatenate along axis 0
520        let concat = concatenate(Axis(0), &[a.view(), b.view()]).unwrap();
521        assert_eq!(concat.shape(), &[4, 2]);
522
523        // Stack along new axis
524        let stacked = ndarray::stack(Axis(0), &[a.view(), b.view()]).unwrap();
525        assert_eq!(stacked.shape(), &[2, 2, 2]);
526    }
527
528    #[test]
529    fn test_zip_operations() {
530        let a = array![1, 2, 3];
531        let b = array![4, 5, 6];
532        let mut c = array![0, 0, 0];
533
534        azip!((a in &a, b in &b, c in &mut c) {
535            *c = a + b;
536        });
537
538        assert_eq!(c, array![5, 7, 9]);
539    }
540}