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}