1#![allow(deprecated)] #![allow(clippy::result_large_err)] #![allow(clippy::needless_range_loop)] #![allow(clippy::too_many_arguments)] #![allow(clippy::identity_op)] #![allow(clippy::approx_constant)] #![allow(clippy::excessive_precision)] pub mod algorithms;
76pub mod array;
77pub mod array_ops;
78pub mod arrays;
79#[cfg(feature = "arrow")]
80pub mod arrow;
81pub mod autodiff;
82pub mod axis_ops;
83pub mod bitwise_ops;
84pub mod blas;
85pub mod char;
86pub mod cluster;
87pub mod comparisons;
88pub mod comparisons_broadcast;
89pub mod complex_ops;
90pub mod conversions;
91pub mod derivative;
92pub mod distance;
93#[cfg(feature = "distributed")]
94pub mod distributed;
95pub mod error;
96pub mod error_handling;
97pub mod expr;
98pub mod fft;
99pub mod financial;
100#[cfg(feature = "gpu")]
101pub mod gpu;
102pub mod indexing;
103pub mod integrate;
104pub mod interop;
105pub mod interpolate;
106pub mod io;
107pub(crate) mod kernels;
108pub mod linalg;
109pub mod linalg_accelerated;
110pub mod linalg_extended;
111pub mod linalg_optimized;
112pub mod linalg_parallel;
113pub mod optimized_ops; pub mod linalg_stable;
116pub mod masked;
117pub mod math;
118pub mod math_extended;
119pub mod matrix;
120pub mod memory_alloc;
121pub mod memory_optimize;
122pub mod mmap;
123pub mod ndimage;
124pub mod nn;
125pub mod ode;
126pub mod optimize;
127pub mod parallel;
128pub mod parallel_optimize;
129pub mod pde;
130pub mod printing;
131#[cfg(feature = "python")]
132pub mod python;
133pub mod random;
134pub mod roots;
135pub mod set_ops;
136pub mod shared_array;
137pub mod signal;
138pub mod simd;
139pub mod simd_optimize;
140pub mod sparse;
141pub mod sparse_enhanced;
142pub mod spatial;
143pub mod special;
144pub mod stats;
145pub mod stride_tricks;
146pub mod symbolic;
147pub mod testing;
148pub mod traits;
149pub mod types;
150pub mod ufunc_ops;
151pub mod ufuncs;
152pub mod unique;
153pub mod unique_optimized;
154pub mod util;
155pub mod views;
156#[cfg(feature = "visualization")]
157pub mod viz;
158#[cfg(feature = "wasm")]
159pub mod wasm;
160
161pub mod new_modules;
164
165pub use error::{NumRs2Error, Result};
166
167pub use random::random_base;
169
170#[cfg(doctest)]
172pub mod doctests {}
173
174pub mod prelude {
176 pub use crate::array::Array;
177 pub use crate::array_ops::*;
178 pub use crate::axis_ops::*;
180 pub use crate::axis_ops::{apply_along_axis, apply_over_axes, vectorize};
181 pub use crate::bitwise_ops::{
182 bitwise_and, bitwise_not, bitwise_or, bitwise_xor, invert, left_shift, left_shift_scalar,
183 right_shift, right_shift_scalar,
184 };
185 pub use crate::char;
186 pub use crate::char::{array_from_strings, StringArray, StringElement};
187 pub use crate::comparisons::{
188 all, allclose, allclose_with_tol, any, array_equal, count_nonzero, equal, flatnonzero,
189 greater, greater_equal, isclose, isclose_array, less, less_equal, logical_and, logical_not,
190 logical_or, logical_xor, not_equal,
191 };
192 pub use crate::complex_ops::{
193 absolute as complex_abs, angle as complex_angle, conj as complex_conj, from_polar,
194 imag as complex_imag, iscomplex, iscomplexobj, isreal, isrealobj, real as complex_real,
195 to_complex,
196 };
197 pub use crate::conversions::*;
198 pub use crate::error::{NumRs2Error, Result};
199 pub use crate::error_handling::{
200 errstate, geterr, geterrcall, handle_error, seterr, seterrcall, ErrorAction, ErrorState,
201 ErrorStateBuilder, ErrorStateGuard, FloatingPointError,
202 };
203 pub use crate::financial::{
204 accrued_interest,
206 amortization_schedule,
208 binomial_option_price,
210 black_scholes,
211 black_scholes_greeks,
212 bond_convexity,
213 bond_duration,
214 bond_equivalent_yield,
215 bond_price,
216 bond_yield,
217 cumipmt,
219 cumprinc,
220 db,
222 ddb,
223 effect,
225 fv,
227 fv_array,
228 implied_volatility,
229 ipmt,
231 irr,
232 irr_multiple_series,
233 mirr,
234 modified_duration,
235 nominal,
236 nper,
237 nper_array,
238 npv,
239 npv_multiple_series,
240 npv_rates,
241 pmt,
242 pmt_array,
243 ppmt,
244 pv,
245 pv_array,
246 rate,
247 rate_array,
248 sln,
250 syd,
251 AmortizationSchedule,
252 };
253 pub use crate::indexing::{
255 diag_indices, diag_indices_from, extract, indices_grid, ix_, mask_indices,
256 put as indexing_put, put_along_axis, putmask as indexing_putmask, ravel_multi_index, take,
257 take_along_axis, tril_indices, tril_indices_from, triu_indices, triu_indices_from,
258 unravel_index, IndexSpec,
259 };
260 pub use crate::io::{array_to_vec2d, vec2d_to_array, vec_to_array, SerializeFormat};
261 #[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
263 pub use crate::linalg::{
264 cholesky as cholesky_basic, eig, inv, qr as qr_basic, solve, svd as svd_basic,
265 };
266 #[cfg(feature = "lapack")]
267 pub use crate::linalg::{det, matrix_power};
268 pub use crate::linalg::{inner, kron, norm, outer, tensordot, trace, vdot};
269
270 #[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
272 pub use crate::linalg::{matrix_rank, pinv};
273 pub use crate::linalg_extended::eigenvalue;
275 pub use crate::linalg_optimized::{lu_optimized, transpose_optimized, OptimizedBlas};
276 pub use crate::linalg_parallel::ParallelLinAlg;
277 pub use crate::linalg_stable::{
278 CholeskyStableResult, QRPivotedResult, SVDStableResult, StableDecompositions,
279 };
280 pub use crate::masked::MaskedArray;
281 pub use crate::ufuncs::{abs, ceil, exp, floor, log, round, sqrt};
283 pub use crate::math_extended::{erf, erfc, gamma, gammaln};
287 pub use crate::math::{
290 amax, amin, angle, arange, argmax, argmin, argpartition, argsort, around, bartlett,
291 bincount, blackman, clip, conj, copysign, cumprod, cumsum, cumulative_prod, cumulative_sum,
292 diff, diff_extended, digitize, divmod, ediff1d, empty, fmod, frexp, gcd, geomspace,
293 gradient, hamming, hanning, heaviside, i0, imag, interp, isfinite, isinf, isnan, kaiser,
294 kurtosis, lcm, ldexp, linspace, logspace, max, mean, median, min, modf, nan_to_num, nanmax,
295 nanmean, nanmin, nanstd, nansum, nanvar, nextafter, nonzero, ones, partition, prod, real,
296 real_if_close, remainder, resize, searchsorted, sinc, skew, sort, std, sum, trapz, var,
297 zeros, ElementWiseMath,
298 };
299 pub use crate::matrix::{
300 asmatrix, matrix, matrix_from_nested, matrix_from_scalar, BandedMatrix, Matrix,
301 };
302 pub use crate::mmap::MmapArray;
303 pub use crate::random::advanced_distributions;
304 pub use crate::random::distributions;
305 pub use crate::random::generator::{
306 default_rng, BitGenerator, Generator, SeedableBitGenerator, StdBitGenerator,
307 };
308 pub use crate::random::{self, RandomState};
309 pub use crate::random::{Philox4x64BitGenerator, SFC64BitGenerator, SeedSequence};
310 pub use crate::set_ops::{
311 in1d, intersect1d, isin, setdiff1d, setxor1d, union1d, unique_axis, unique_with_options,
312 };
313 pub use crate::signal::{convolve, convolve2d, correlate, correlate2d};
314 pub use crate::simd::get_simd_implementation_name;
316 pub use crate::sparse;
317 pub use crate::sparse_enhanced::SparseOpsAdvanced;
318 pub use crate::stats::{
320 average, corrcoef, cov, histogram, histogram_dd, max_along_axis, min_along_axis, mode,
321 percentile, ptp, quantile, HistBins, Statistics,
322 };
323 pub use crate::stride_tricks::{
324 as_strided, broadcast_arrays, broadcast_to, byte_strides, set_strides, sliding_window_view,
325 };
326 pub use crate::testing::{
328 arrays_close, assert_array_all_finite, assert_array_almost_equal, assert_array_equal,
329 assert_array_no_nan, assert_array_same_shape, assert_scalar_almost_equal, is_finite_array,
330 test_summary, tolerances, TestResult, ToleranceConfig,
331 };
332 pub use crate::run_tests;
334 pub use crate::traits::{
336 ArrayIndexing, ArrayMath, ArrayOps, ArrayReduction, ComplexElement, FloatingPoint,
337 IntegerElement, LinearAlgebra, MatrixDecomposition, NumericElement,
338 };
339 pub use crate::ufuncs::{
342 absolute, add, add_scalar, arctan2, cbrt, divide, divide_scalar, dot, exp2, expm1, fma,
343 hypot, log10, log1p, log2, maximum, minimum, multiply, multiply_scalar, negative, norm_l1,
344 norm_l2, power, power_scalar, reciprocal, subtract, subtract_scalar, BinaryUfunc,
345 UnaryUfunc,
346 };
347 pub use crate::ufunc_ops::{
349 add_where, divide_where, multiply_where, subtract_where, ufunc_accumulate, ufunc_at,
350 ufunc_outer, ufunc_reduce, ufunc_reduceat, ufunc_where, UfuncOp,
351 };
352 pub use crate::unique::{unique, UniqueResult};
353 pub use crate::unique_optimized::unique_optimized;
354 pub use crate::util::{
355 astype, can_operate_inplace, fast_sum, optimize_layout, parallel_map, MemoryLayout,
356 };
357 pub use crate::views::*;
358
359 pub use crate::interop::ndarray_compat::{from_ndarray, to_ndarray};
362 pub use crate::memory_optimize::{
366 align_data, optimize_layout as memory_optimize_layout, optimize_placement,
367 AlignmentStrategy, LayoutStrategy, PlacementStrategy,
368 };
369
370 pub use crate::parallel_optimize::{
372 adaptive_threshold, optimize_parallel_computation, optimize_scheduling, partition_workload,
373 };
374 pub use crate::parallel_optimize::{
375 ParallelConfig, ParallelizationThreshold, SchedulingStrategy, WorkloadPartitioning,
376 };
377
378 pub use crate::printing::{
380 array_str, get_printoptions, reset_printoptions, set_printoptions, PrintOptions,
381 };
382
383 pub use crate::memory_alloc::{
385 get_default_allocator, get_global_allocator_strategy, init_global_allocator,
386 reset_global_allocator,
387 };
388 pub use crate::memory_alloc::{
389 AlignedAllocator, AlignmentConfig, AllocStrategy, ArenaAllocator, ArenaConfig, CacheConfig,
390 CacheLevel, CacheOptimizedAllocator, PoolAllocator, PoolConfig,
391 };
392
393 pub use crate::algorithms::{
395 BandwidthEstimate, BandwidthOptimizer, CacheAwareArrayOps, CacheAwareConvolution,
396 CacheAwareFFT, MemoryOperation,
397 };
398
399 pub use crate::parallel::parallel_algorithms::ParallelConfig as ParallelAlgorithmConfig;
401 pub use crate::parallel::{
402 global_parallel_context, initialize_parallel_context, shutdown_parallel_context, task,
403 BalancingStrategy, LoadBalancer, ParallelAllocator, ParallelAllocatorConfig,
404 ParallelArrayOps, ParallelContext, ParallelFFT, ParallelMatrixOps, ParallelScheduler,
405 SchedulerConfig, Task, TaskPriority, TaskResult, ThreadLocalAllocator, WorkStealingPool,
406 WorkloadMetrics,
407 };
408
409 pub use crate::memory_alloc::{
411 EnhancedAllocatorBridge, IntelligentAllocationStrategy, NumericalArrayAllocator,
412 };
413 pub use crate::traits::{
414 AllocationFrequency, AllocationLifetime, AllocationRequirements, AllocationStats,
415 AllocationStrategy, MemoryAllocator, MemoryAware, MemoryOptimization, MemoryUsage,
416 OptimizationType, SpecializedAllocator, ThreadingRequirements,
417 };
418
419 pub use crate::fft::FFT;
421 #[cfg(feature = "lapack")]
422 pub use crate::new_modules::eigenvalues::{eig as eig_general, eigh, eigvals, eigvalsh};
423 #[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
424 pub use crate::new_modules::matrix_decomp::{
425 cholesky, cod, condition_number, lu, pivoted_cholesky, qr, rcond, schur, svd,
426 };
427 pub use crate::new_modules::polynomial::{
428 poly, polyadd, polychebyshev, polycompanion, polycompose, polyder, polydiv, polyextrap,
429 polyfit, polyfit_weighted, polyfromroots, polygcd, polygrid2d, polyhermite, polyint,
430 polyjacobi, polylaguerre, polylegendre, polymul, polymulx, polypower, polyresidual,
431 polyscale, polysub, polytrim, polyval2d, polyvander, polyvander2d, CubicSpline, Polynomial,
432 PolynomialInterpolation,
433 };
434
435 #[cfg(feature = "lapack")]
437 pub use crate::optimized_ops::parallel_matrix_ops;
438 pub use crate::optimized_ops::{
439 adaptive_array_sum, chunked_array_processing, get_optimization_info,
440 parallel_column_statistics, should_use_parallel, simd_elementwise_ops, simd_matmul,
441 simd_vector_ops, ColumnStats, SimdOpsResult, SimdVectorResult,
442 };
443
444 #[cfg(feature = "gpu")]
446 pub use crate::gpu::{
447 add as gpu_add, divide as gpu_divide, matmul, multiply as gpu_multiply,
448 subtract as gpu_subtract, transpose, GpuArray, GpuContext,
449 };
450 pub use crate::new_modules::sparse::{SparseArray, SparseMatrix, SparseMatrixFormat};
451 pub use crate::new_modules::special::{
452 airy_ai, airy_bi, associated_legendre_p, bessel_i, bessel_j, bessel_k, bessel_y, beta,
453 betainc, digamma, ellipe, ellipeinc, ellipf, ellipk, erfcinv, erfinv, exp1, expi, fresnel,
454 gammainc, jacobi_elliptic, lambertw, lambertwm1, legendre_p, polylog, shichi, sici,
455 spherical_harmonic, struve_h, zeta,
456 };
457 pub use crate::arrays::{
461 ArrayView, BooleanCombineOp, BroadcastEngine, BroadcastOp, BroadcastReduction,
462 FancyIndexEngine, FancyIndexResult, ResolvedIndex, Shape, SpecializedIndexing,
463 };
464
465 pub use crate::types::custom::CustomDType;
467 pub use crate::types::datetime::{
468 business_days,
469 datetime64,
471 datetime_array,
472 datetime_as_string,
473 datetime_data,
474 timedelta64,
475 DateTime64,
476 DateTimeUnit,
477 DateUnit,
478 TimeDelta64,
479 Timezone,
480 TimezoneDateTime,
481 };
482 pub use crate::types::structured::{DType, Field, RecordArray, StructuredArray};
483
484 pub use crate::shared_array::{SharedArray, SharedArrayView};
486
487 pub use crate::expr::{
489 ArrayExpr,
490 BinaryExpr,
491 CSEOptimizer,
492 CSESupport,
493 CachedExpr,
495 Expr,
497 ExprBuilder,
499 ExprCache,
500 ExprId,
501 ExprKey,
502 IntoExpr,
504 LazyEval,
505 ScalarExpr,
506 SharedArrayExpr,
507 SharedBinaryExpr,
508 SharedExpr,
510 SharedExprBuilder,
511 SharedScalarExpr,
512 SharedUnaryExpr,
513 UnaryExpr,
514 };
515
516 pub use crate::memory_optimize::access_patterns::{
520 cache_aware_binary_op, cache_aware_copy, cache_aware_transform, detect_layout,
521 AccessPattern, AccessStats, Block, BlockedIterator, OptimizationHints, StrideOptimizer,
522 Tile2D, TiledIterator2D,
523 };
524
525 pub use scirs2_core::ndarray::{Axis, Dimension, IxDyn, ShapeBuilder};
527 pub use scirs2_core::{Complex, Complex64};
529}
530
531#[cfg(test)]
532mod tests {
533 use crate::prelude::*;
534 use crate::simd::{simd_add, simd_div, simd_mul, simd_prod, simd_sqrt, simd_sum};
535 use approx::assert_relative_eq;
536
537 #[test]
538 fn basic_array_ops() {
539 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
540 let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
541
542 let c = a.add(&b);
544 assert_eq!(c.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
545
546 let d = a.subtract(&b);
548 assert_eq!(d.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
549
550 let e = a.multiply(&b);
552 assert_eq!(e.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
553
554 let f = a.divide(&b);
556 assert_relative_eq!(f.to_vec()[0], 0.2, epsilon = 1e-10);
557 assert_relative_eq!(f.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
558 assert_relative_eq!(f.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
559 assert_relative_eq!(f.to_vec()[3], 0.5, epsilon = 1e-10);
560 }
561
562 #[test]
563 fn test_broadcasting() {
564 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
566
567 let b = a.add_scalar(5.0);
569 assert_eq!(b.to_vec(), vec![6.0, 7.0, 8.0]);
570
571 let c = a.multiply_scalar(2.0);
573 assert_eq!(c.to_vec(), vec![2.0, 4.0, 6.0]);
574
575 let row = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[1, 3]);
577 let col = Array::<f64>::from_vec(vec![4.0, 5.0]).reshape(&[2, 1]);
578
579 let result = row
581 .add_broadcast(&col)
582 .expect("test: broadcast addition should succeed");
583 assert_eq!(result.shape(), vec![2, 3]);
584 assert_eq!(result.to_vec(), vec![5.0, 6.0, 7.0, 6.0, 7.0, 8.0]);
585
586 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
588 let b = Array::<f64>::from_vec(vec![10.0, 20.0]).reshape(&[1, 2]);
589
590 let result = a
592 .multiply_broadcast(&b)
593 .expect("test: broadcast multiplication should succeed");
594 assert_eq!(result.shape(), vec![2, 2]);
595 assert_eq!(result.to_vec(), vec![10.0, 40.0, 30.0, 80.0]);
596
597 let shape1 = vec![3, 1, 4];
599 let shape2 = vec![2, 1];
600 let broadcast_shape = Array::<f64>::broadcast_shape(&shape1, &shape2)
601 .expect("test: broadcast shape computation should succeed");
602 assert_eq!(broadcast_shape, vec![3, 2, 4]);
603 }
604
605 #[test]
606 fn test_array_creation() {
607 let zeros = Array::<f64>::zeros(&[2, 3]);
609 assert_eq!(zeros.shape(), vec![2, 3]);
610 assert_eq!(zeros.to_vec(), vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
611
612 let ones = Array::<f64>::ones(&[2, 2]);
614 assert_eq!(ones.shape(), vec![2, 2]);
615 assert_eq!(ones.to_vec(), vec![1.0, 1.0, 1.0, 1.0]);
616
617 let fives = Array::<f64>::full(&[2, 2], 5.0);
619 assert_eq!(fives.shape(), vec![2, 2]);
620 assert_eq!(fives.to_vec(), vec![5.0, 5.0, 5.0, 5.0]);
621
622 let arr = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
624 let reshaped = arr.reshape(&[2, 3]);
625 assert_eq!(reshaped.shape(), vec![2, 3]);
626 assert_eq!(reshaped.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
627 }
628
629 #[test]
630 fn test_array_methods() {
631 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).reshape(&[2, 3]);
632
633 assert_eq!(a.shape(), vec![2, 3]);
635 assert_eq!(a.ndim(), 2);
636 assert_eq!(a.size(), 6);
637
638 let at = a.transpose();
640 assert_eq!(at.shape(), vec![3, 2]);
641
642 let at_vec = at.to_vec();
645 assert_eq!(at_vec.len(), 6);
646 assert!(at_vec.contains(&1.0));
647 assert!(at_vec.contains(&2.0));
648 assert!(at_vec.contains(&3.0));
649 assert!(at_vec.contains(&4.0));
650 assert!(at_vec.contains(&5.0));
651 assert!(at_vec.contains(&6.0));
652
653 let slice = a
655 .slice(0, 1)
656 .expect("test: slice should succeed for valid axis");
657 assert_eq!(slice.shape(), vec![3]);
658 assert_eq!(slice.to_vec(), vec![4.0, 5.0, 6.0]);
659 }
660
661 #[test]
662 fn test_map_operations() {
663 let a = Array::<f64>::from_vec(vec![1.0, 4.0, 9.0, 16.0]);
664
665 let sqrt_a = a.map(|x| x.sqrt());
667 assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
668 assert_relative_eq!(sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
669 assert_relative_eq!(sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
670 assert_relative_eq!(sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
671
672 let par_sqrt_a = a.par_map(|x| x.sqrt());
674 assert_relative_eq!(par_sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
675 assert_relative_eq!(par_sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
676 assert_relative_eq!(par_sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
677 assert_relative_eq!(par_sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
678 }
679
680 #[cfg(feature = "lapack")]
681 #[test]
682 fn test_linalg_ops() {
683 let a = Array::<f64>::from_vec(vec![4.0, 7.0, 2.0, 6.0]).reshape(&[2, 2]);
685
686 let det_a = det(&a).expect("test: determinant computation should succeed");
688 assert_relative_eq!(det_a, 10.0, epsilon = 1e-10);
689
690 let inv_a = inv(&a).expect("test: matrix inverse should succeed for invertible matrix");
692 let expected_inv = [0.6, -0.7, -0.2, 0.4];
693 for (actual, expected) in inv_a.to_vec().iter().zip(expected_inv.iter()) {
694 assert_relative_eq!(*actual, *expected, epsilon = 1e-10);
695 }
696
697 let identity = a
699 .matmul(&inv_a)
700 .expect("test: matrix multiplication should succeed");
701 assert_relative_eq!(identity.to_vec()[0], 1.0, epsilon = 1e-10);
702 assert_relative_eq!(identity.to_vec()[1], 0.0, epsilon = 1e-10);
703 assert_relative_eq!(identity.to_vec()[2], 0.0, epsilon = 1e-10);
704 assert_relative_eq!(identity.to_vec()[3], 1.0, epsilon = 1e-10);
705
706 let b = Array::<f64>::from_vec(vec![1.0, 3.0]);
708 let x = solve(&a, &b).expect("test: linear system solve should succeed");
709
710 assert_relative_eq!(x.to_vec()[0], -1.5, epsilon = 1e-10);
712 assert_relative_eq!(x.to_vec()[1], 1.0, epsilon = 1e-10);
713
714 let b_check = a
716 .matmul(&x.reshape(&[2, 1]))
717 .expect("test: matrix-vector multiplication should succeed")
718 .reshape(&[2]);
719 assert_relative_eq!(b_check.to_vec()[0], b.to_vec()[0], epsilon = 1e-10);
720 assert_relative_eq!(b_check.to_vec()[1], b.to_vec()[1], epsilon = 1e-10);
721 }
722
723 #[test]
724 fn test_tensor_operations() {
725 let a = Array::<f64>::from_vec(vec![1.0, 2.0]).reshape(&[1, 2]);
727 let b = Array::<f64>::from_vec(vec![3.0, 4.0]).reshape(&[2, 1]);
728
729 let kron_result = kron(&a, &b).expect("test: Kronecker product should succeed");
730 assert_eq!(kron_result.shape(), &[2, 2]);
731 assert_eq!(kron_result.to_vec(), vec![3.0, 6.0, 4.0, 8.0]);
732
733 let tensordot_result = tensordot(&a, &b, &[1, 0]).expect("test: tensordot should succeed");
735 assert_eq!(tensordot_result.shape(), &[1, 1]);
736 assert_relative_eq!(tensordot_result.to_vec()[0], 11.0, epsilon = 1e-10);
737 }
738
739 #[test]
740 fn test_matrix_operations() {
741 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
743 let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
744
745 let c = a
747 .matmul(&b)
748 .expect("test: matrix multiplication should succeed");
749 assert_eq!(c.shape(), vec![2, 2]);
750 assert_eq!(c.to_vec(), vec![19.0, 22.0, 43.0, 50.0]);
751
752 let v = Array::<f64>::from_vec(vec![1.0, 2.0]);
754 let result = a
755 .matmul(&v.reshape(&[2, 1]))
756 .expect("test: matrix-vector multiplication should succeed")
757 .reshape(&[2]);
758 assert_eq!(result.to_vec(), vec![5.0, 11.0]);
759 }
760
761 #[test]
762 fn test_simd_operations() {
763 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
764 let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]);
765
766 let c = simd_add(&a, &b).expect("test: SIMD addition should succeed");
768 assert_eq!(c.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
769
770 let d = simd_mul(&a, &b).expect("test: SIMD multiplication should succeed");
772 assert_eq!(d.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
773
774 let e = simd_div(&a, &b).expect("test: SIMD division should succeed");
776 assert_relative_eq!(e.to_vec()[0], 0.2, epsilon = 1e-10);
777 assert_relative_eq!(e.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
778 assert_relative_eq!(e.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
779 assert_relative_eq!(e.to_vec()[3], 0.5, epsilon = 1e-10);
780
781 let sqrt_a = simd_sqrt(&a);
783 assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
784 assert_relative_eq!(
785 sqrt_a.to_vec()[1],
786 std::f64::consts::SQRT_2,
787 epsilon = 1e-10
788 );
789 assert_relative_eq!(sqrt_a.to_vec()[2], 1.7320508075688772, epsilon = 1e-10);
790 assert_relative_eq!(sqrt_a.to_vec()[3], 2.0, epsilon = 1e-10);
791
792 assert_eq!(simd_sum(&a), 10.0);
794 assert_eq!(simd_prod(&a), 24.0);
795 }
796
797 #[test]
798 fn test_norm_functions() {
799 let v = Array::<f64>::from_vec(vec![3.0, 4.0]);
801
802 let norm_1 = norm(&v, Some(1.0)).expect("test: L1 norm computation should succeed");
804 assert_relative_eq!(norm_1, 7.0, epsilon = 1e-10);
805
806 let norm_2 = norm(&v, Some(2.0)).expect("test: L2 norm computation should succeed");
808 assert_relative_eq!(norm_2, 5.0, epsilon = 1e-10);
809
810 let norm_inf =
812 norm(&v, Some(f64::INFINITY)).expect("test: infinity norm computation should succeed");
813 assert_relative_eq!(norm_inf, 4.0, epsilon = 1e-10);
814
815 let m = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
817
818 let matrix_norm_1 =
820 norm(&m, Some(1.0)).expect("test: matrix L1 norm computation should succeed");
821 assert_relative_eq!(matrix_norm_1, 6.0, epsilon = 1e-10);
822
823 let matrix_norm_inf = norm(&m, Some(f64::INFINITY))
825 .expect("test: matrix infinity norm computation should succeed");
826 assert_relative_eq!(matrix_norm_inf, 7.0, epsilon = 1e-10);
827 }
828
829 #[test]
830 fn test_math_operations() {
831 use crate::math::*;
832
833 let a = Array::<f64>::from_vec(vec![1.0, 4.0, 9.0, 16.0]);
835
836 let neg_a = a.map(|x| -x);
838 let abs_a = neg_a.abs();
839 for (expected, actual) in a.to_vec().iter().zip(abs_a.to_vec().iter()) {
840 assert_relative_eq!(*expected, *actual, epsilon = 1e-10);
841 }
842
843 let exp_a = a.exp();
845 assert_relative_eq!(exp_a.to_vec()[0], 1.0_f64.exp(), epsilon = 1e-10);
846 assert_relative_eq!(exp_a.to_vec()[1], 4.0_f64.exp(), epsilon = 1e-10);
847 assert_relative_eq!(exp_a.to_vec()[2], 9.0_f64.exp(), epsilon = 1e-10);
848 assert_relative_eq!(exp_a.to_vec()[3], 16.0_f64.exp(), epsilon = 1e-10);
849
850 let log_a = a.log();
852 assert_relative_eq!(log_a.to_vec()[0], 1.0_f64.ln(), epsilon = 1e-10);
853 assert_relative_eq!(log_a.to_vec()[1], 4.0_f64.ln(), epsilon = 1e-10);
854 assert_relative_eq!(log_a.to_vec()[2], 9.0_f64.ln(), epsilon = 1e-10);
855 assert_relative_eq!(log_a.to_vec()[3], 16.0_f64.ln(), epsilon = 1e-10);
856
857 let sqrt_a = a.sqrt();
859 assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
860 assert_relative_eq!(sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
861 assert_relative_eq!(sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
862 assert_relative_eq!(sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
863
864 let pow_a = a.pow(2.0);
866 assert_relative_eq!(pow_a.to_vec()[0], 1.0, epsilon = 1e-10);
867 assert_relative_eq!(pow_a.to_vec()[1], 16.0, epsilon = 1e-10);
868 assert_relative_eq!(pow_a.to_vec()[2], 81.0, epsilon = 1e-10);
869 assert_relative_eq!(pow_a.to_vec()[3], 256.0, epsilon = 1e-10);
870
871 let angles = Array::<f64>::from_vec(vec![
873 0.0,
874 std::f64::consts::PI / 6.0,
875 std::f64::consts::PI / 4.0,
876 std::f64::consts::PI / 3.0,
877 ]);
878
879 let sin_angles = angles.sin();
880 assert_relative_eq!(sin_angles.to_vec()[0], 0.0, epsilon = 1e-10);
881 assert_relative_eq!(sin_angles.to_vec()[1], 0.5, epsilon = 1e-10);
882 assert_relative_eq!(
883 sin_angles.to_vec()[2],
884 1.0 / std::f64::consts::SQRT_2,
885 epsilon = 1e-10
886 );
887 assert_relative_eq!(sin_angles.to_vec()[3], 0.8660254037844386, epsilon = 1e-10);
888
889 let cos_angles = angles.cos();
890 assert_relative_eq!(cos_angles.to_vec()[0], 1.0, epsilon = 1e-10);
891 assert_relative_eq!(cos_angles.to_vec()[1], 0.8660254037844386, epsilon = 1e-10);
892 assert_relative_eq!(
893 cos_angles.to_vec()[2],
894 1.0 / std::f64::consts::SQRT_2,
895 epsilon = 1e-10
896 );
897 assert_relative_eq!(cos_angles.to_vec()[3], 0.5, epsilon = 1e-10);
898
899 let lin = linspace(0.0, 10.0, 6);
901 assert_eq!(lin.size(), 6);
902 assert_relative_eq!(lin.to_vec()[0], 0.0, epsilon = 1e-10);
903 assert_relative_eq!(lin.to_vec()[1], 2.0, epsilon = 1e-10);
904 assert_relative_eq!(lin.to_vec()[2], 4.0, epsilon = 1e-10);
905 assert_relative_eq!(lin.to_vec()[3], 6.0, epsilon = 1e-10);
906 assert_relative_eq!(lin.to_vec()[4], 8.0, epsilon = 1e-10);
907 assert_relative_eq!(lin.to_vec()[5], 10.0, epsilon = 1e-10);
908
909 let range = arange(0.0, 5.0, 1.0);
911 assert_eq!(range.size(), 5);
912 assert_eq!(range.to_vec(), vec![0.0, 1.0, 2.0, 3.0, 4.0]);
913
914 let rev_range = arange(5.0, 0.0, -1.0);
916 assert_eq!(rev_range.size(), 5);
917 assert_eq!(rev_range.to_vec(), vec![5.0, 4.0, 3.0, 2.0, 1.0]);
918
919 let log_space = logspace(0.0, 3.0, 4, None);
921 assert_eq!(log_space.size(), 4);
922 assert_relative_eq!(log_space.to_vec()[0], 1.0, epsilon = 1e-10);
923 assert_relative_eq!(log_space.to_vec()[1], 10.0, epsilon = 1e-10);
924 assert_relative_eq!(log_space.to_vec()[2], 100.0, epsilon = 1e-10);
925 assert_relative_eq!(log_space.to_vec()[3], 1000.0, epsilon = 1e-10);
926
927 let geom_space = geomspace(1.0, 1000.0, 4);
929 assert_eq!(geom_space.size(), 4);
930 assert_relative_eq!(geom_space.to_vec()[0], 1.0, epsilon = 1e-10);
931 assert_relative_eq!(geom_space.to_vec()[1], 10.0, epsilon = 1e-10);
932 assert_relative_eq!(geom_space.to_vec()[2], 100.0, epsilon = 1e-10);
933 assert_relative_eq!(geom_space.to_vec()[3], 1000.0, epsilon = 1e-10);
934 }
935
936 #[test]
937 fn test_array_operations() {
938 use crate::array_ops::*;
939
940 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
942 let tiled = tile(&a, &[2]).expect("test: tile operation should succeed");
943 assert_eq!(tiled.shape(), vec![6]);
944 assert_eq!(tiled.to_vec(), vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
945
946 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
947 let tiled_2d = tile(&a_2d, &[2, 1]).expect("test: 2D tile operation should succeed");
948 assert_eq!(tiled_2d.shape(), vec![4, 2]);
949 assert_eq!(
950 tiled_2d.to_vec(),
951 vec![1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0]
952 );
953
954 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
956 let repeated = repeat(&a, 2, None).expect("test: repeat operation should succeed");
957 assert_eq!(repeated.shape(), vec![6]);
958 assert_eq!(repeated.to_vec(), vec![1.0, 1.0, 2.0, 2.0, 3.0, 3.0]);
959
960 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
961 let repeated_axis0 =
962 repeat(&a_2d, 2, Some(0)).expect("test: repeat along axis 0 should succeed");
963 assert_eq!(repeated_axis0.shape(), vec![4, 2]);
964 assert_eq!(
965 repeated_axis0.to_vec(),
966 vec![1.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 4.0]
967 );
968
969 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
971 let b = Array::<f64>::from_vec(vec![4.0, 5.0, 6.0]);
972 let c = concatenate(&[&a, &b], 0).expect("test: concatenate should succeed");
973 assert_eq!(c.shape(), vec![6]);
974 assert_eq!(c.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
975
976 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
977 let b_2d = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
978 let c_axis0 =
979 concatenate(&[&a_2d, &b_2d], 0).expect("test: concatenate along axis 0 should succeed");
980 assert_eq!(c_axis0.shape(), vec![4, 2]);
981 assert_eq!(
982 c_axis0.to_vec(),
983 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
984 );
985
986 let c_axis1 =
987 concatenate(&[&a_2d, &b_2d], 1).expect("test: concatenate along axis 1 should succeed");
988 assert_eq!(c_axis1.shape(), vec![2, 4]);
989 let c_vec = c_axis1.to_vec();
990 assert_eq!(c_vec.len(), 8);
992 assert!(c_vec.contains(&1.0));
993 assert!(c_vec.contains(&2.0));
994 assert!(c_vec.contains(&3.0));
995 assert!(c_vec.contains(&4.0));
996 assert!(c_vec.contains(&5.0));
997 assert!(c_vec.contains(&6.0));
998 assert!(c_vec.contains(&7.0));
999 assert!(c_vec.contains(&8.0));
1000
1001 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
1003 let b = Array::<f64>::from_vec(vec![4.0, 5.0, 6.0]);
1004 let c = stack(&[&a, &b], 0).expect("test: stack along axis 0 should succeed");
1005 assert_eq!(c.shape(), vec![2, 3]);
1006 let c_vec = c.to_vec();
1007 assert_eq!(c_vec.len(), 6);
1009 assert!(c_vec.contains(&1.0));
1010 assert!(c_vec.contains(&2.0));
1011 assert!(c_vec.contains(&3.0));
1012 assert!(c_vec.contains(&4.0));
1013 assert!(c_vec.contains(&5.0));
1014 assert!(c_vec.contains(&6.0));
1015
1016 let d = stack(&[&a, &b], 1).expect("test: stack along axis 1 should succeed");
1017 assert_eq!(d.shape(), vec![3, 2]);
1018 let d_vec = d.to_vec();
1019 assert_eq!(d_vec.len(), 6);
1021 assert!(d_vec.contains(&1.0));
1022 assert!(d_vec.contains(&2.0));
1023 assert!(d_vec.contains(&3.0));
1024 assert!(d_vec.contains(&4.0));
1025 assert!(d_vec.contains(&5.0));
1026 assert!(d_vec.contains(&6.0));
1027
1028 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1030 let splits = split(&a, &[2, 4], 0).expect("test: split should succeed");
1031 assert_eq!(splits.len(), 3);
1032 assert_eq!(splits[0].to_vec(), vec![1.0, 2.0]);
1033 assert_eq!(splits[1].to_vec(), vec![3.0, 4.0]);
1034 assert_eq!(splits[2].to_vec(), vec![5.0, 6.0]);
1035
1036 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).reshape(&[2, 3]);
1037 let splits_a =
1039 split(&a, &[2, 4], 0).expect("test: split with multiple indices should succeed");
1040 assert_eq!(splits_a.len(), 3);
1041
1042 let splits_axis1 = split(&a_2d, &[1], 1).expect("test: split along axis 1 should succeed");
1043 assert_eq!(splits_axis1.len(), 2);
1044 assert_eq!(splits_axis1[0].shape(), vec![2, 1]);
1049 assert_eq!(splits_axis1[1].shape(), vec![2, 2]);
1050 assert_eq!(splits_axis1[0].to_vec(), vec![1.0, 4.0]);
1051 assert_eq!(splits_axis1[1].to_vec(), vec![2.0, 3.0, 5.0, 6.0]);
1052
1053 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
1055 let expanded = expand_dims(&a, 0).expect("test: expand_dims should succeed");
1056 assert_eq!(expanded.shape(), vec![1, 3]);
1057 assert_eq!(expanded.to_vec(), vec![1.0, 2.0, 3.0]);
1058
1059 let expanded_end = expand_dims(&a, 1).expect("test: expand_dims at end should succeed");
1060 assert_eq!(expanded_end.shape(), vec![3, 1]);
1061 assert_eq!(expanded_end.to_vec(), vec![1.0, 2.0, 3.0]);
1062
1063 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[1, 3, 1]);
1065 let squeezed = squeeze(&a, None).expect("test: squeeze should succeed");
1066 assert_eq!(squeezed.shape(), vec![3]);
1067 assert_eq!(squeezed.to_vec(), vec![1.0, 2.0, 3.0]);
1068
1069 let squeezed_axis = squeeze(&a, Some(0)).expect("test: squeeze at axis 0 should succeed");
1070 assert_eq!(squeezed_axis.shape(), vec![3, 1]);
1071 assert_eq!(squeezed_axis.to_vec(), vec![1.0, 2.0, 3.0]);
1072 }
1073
1074 #[test]
1075 fn test_statistics_functions() {
1076 use crate::stats::*;
1077
1078 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1080
1081 assert_relative_eq!(a.mean(), 3.0, epsilon = 1e-10);
1083
1084 assert_relative_eq!(a.var(), 2.0, epsilon = 1e-10);
1086
1087 assert_relative_eq!(a.std(), std::f64::consts::SQRT_2, epsilon = 1e-10);
1089
1090 assert_relative_eq!(a.min(), 1.0, epsilon = 1e-10);
1092 assert_relative_eq!(a.max(), 5.0, epsilon = 1e-10);
1093
1094 assert_relative_eq!(a.percentile(0.0), 1.0, epsilon = 1e-10);
1096 assert_relative_eq!(a.percentile(0.5), 3.0, epsilon = 1e-10);
1097 assert_relative_eq!(a.percentile(1.0), 5.0, epsilon = 1e-10);
1098 assert_relative_eq!(a.percentile(0.25), 2.0, epsilon = 1e-10);
1099 assert_relative_eq!(a.percentile(0.75), 4.0, epsilon = 1e-10);
1100
1101 let b = Array::<f64>::from_vec(vec![5.0, 4.0, 3.0, 2.0, 1.0]);
1103 let cov_result =
1104 cov(&a, Some(&b), None, None, None).expect("test: covariance should succeed");
1105 assert_relative_eq!(
1106 cov_result
1107 .get(&[0, 1])
1108 .expect("test: cov element access should succeed"),
1109 -2.5,
1110 epsilon = 1e-10
1111 );
1112 let corrcoef_result =
1113 corrcoef(&a, Some(&b), None).expect("test: correlation coefficient should succeed");
1114 assert_relative_eq!(
1115 corrcoef_result
1116 .get(&[0, 1])
1117 .expect("test: corrcoef element access should succeed"),
1118 -1.0,
1119 epsilon = 1e-10
1120 );
1121
1122 let data = Array::<f64>::from_vec(vec![1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]);
1124 let (counts, bins) =
1125 histogram(&data, 4, None, None, None).expect("test: histogram should succeed");
1126 assert_eq!(counts.to_vec(), vec![2.0, 2.0, 2.0, 3.0]);
1127 assert_eq!(bins.size(), 5);
1128 assert_relative_eq!(bins.to_vec()[0], 1.0, epsilon = 1e-10);
1129 assert_relative_eq!(bins.to_vec()[4], 5.0, epsilon = 1e-10);
1130 }
1131
1132 #[test]
1133 fn test_boolean_indexing() {
1134 use crate::indexing::*;
1135
1136 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
1138
1139 let mask = vec![true, false, true, false, true];
1141
1142 let _bool_array = Array::<bool>::from_vec(mask.clone());
1145
1146 let mut filtered = Array::<f64>::zeros(&[5]);
1148 let values = Array::<f64>::from_vec(vec![1.0, 3.0, 5.0]);
1149
1150 let mut value_idx = 0;
1152 for (i, &m) in mask.iter().enumerate() {
1153 if m {
1154 filtered
1155 .set(
1156 &[i],
1157 values
1158 .get(&[value_idx])
1159 .expect("test: value access should succeed"),
1160 )
1161 .expect("test: set filtered value should succeed");
1162 value_idx += 1;
1163 }
1164 }
1165
1166 assert_eq!(filtered.to_vec(), vec![1.0, 0.0, 3.0, 0.0, 5.0]);
1168
1169 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
1171 .reshape(&[3, 3]);
1172
1173 let _row_indices = [0]; let _col_indices = [0]; let row_result = a_2d
1179 .index(&[IndexSpec::Index(0), IndexSpec::All])
1180 .expect("test: row indexing should succeed");
1181 assert_eq!(row_result.shape(), vec![3]); let row_vec = row_result.to_vec();
1185 assert_eq!(row_vec.len(), 3);
1186 assert_eq!(row_vec, vec![1.0, 2.0, 3.0]);
1187
1188 let col_result = a_2d
1189 .index(&[IndexSpec::All, IndexSpec::Index(0)])
1190 .expect("test: column indexing should succeed");
1191 assert_eq!(col_result.shape(), vec![3]); assert_eq!(col_result.to_vec(), vec![1.0, 4.0, 7.0]);
1193
1194 let mut a_copy = a.clone();
1196 a_copy
1197 .set_mask(
1198 &Array::<bool>::from_vec(vec![true, false, true, false, true]),
1199 &Array::<f64>::from_vec(vec![10.0, 30.0, 50.0]),
1200 )
1201 .expect("test: set_mask should succeed");
1202
1203 assert_eq!(a_copy.to_vec(), vec![10.0, 2.0, 30.0, 4.0, 50.0]);
1204 }
1205
1206 #[test]
1207 fn test_fancy_indexing() {
1208 use crate::indexing::*;
1209
1210 let _a = Array::<f64>::from_vec(vec![10.0, 20.0, 30.0, 40.0, 50.0]);
1212
1213 let _indices = [0, 1, 2];
1216 let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
1220 .reshape(&[3, 3]);
1221
1222 let single_element = a_2d
1224 .index(&[IndexSpec::Index(1), IndexSpec::Index(1)])
1225 .expect("test: single element indexing should succeed");
1226 assert_eq!(single_element.to_vec(), vec![5.0]);
1227
1228 let slice_result = a_2d
1230 .index(&[IndexSpec::Slice(0, Some(2), None), IndexSpec::All])
1231 .expect("test: slice indexing should succeed");
1232 assert_eq!(slice_result.shape(), vec![2, 3]);
1233 assert_eq!(slice_result.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1234 }
1235
1236 #[test]
1237 fn test_axis_operations() {
1238 use crate::axis_ops::*;
1239
1240 let mut array = Array::<f64>::zeros(&[2, 3]);
1242 array
1243 .set(&[0, 0], 1.0)
1244 .expect("test: set [0,0] should succeed");
1245 array
1246 .set(&[0, 1], 2.0)
1247 .expect("test: set [0,1] should succeed");
1248 array
1249 .set(&[0, 2], 3.0)
1250 .expect("test: set [0,2] should succeed");
1251 array
1252 .set(&[1, 0], 4.0)
1253 .expect("test: set [1,0] should succeed");
1254 array
1255 .set(&[1, 1], 5.0)
1256 .expect("test: set [1,1] should succeed");
1257 array
1258 .set(&[1, 2], 6.0)
1259 .expect("test: set [1,2] should succeed");
1260
1261 let sum_axis0 = array.sum_axis(0).expect("test: sum_axis(0) should succeed");
1263 assert_eq!(sum_axis0.shape(), vec![3]);
1264 assert_eq!(sum_axis0.to_vec(), vec![5.0, 7.0, 9.0]);
1265
1266 let sum_axis1 = array.sum_axis(1).expect("test: sum_axis(1) should succeed");
1268 assert_eq!(sum_axis1.shape(), vec![2]);
1269 assert_eq!(sum_axis1.to_vec(), vec![6.0, 15.0]);
1270
1271 let mean_axis0 = array
1273 .mean_axis(Some(0))
1274 .expect("test: mean_axis(Some(0)) should succeed");
1275 assert_eq!(mean_axis0.shape(), vec![3]);
1276 assert_eq!(mean_axis0.to_vec(), vec![2.5, 3.5, 4.5]);
1277
1278 let mean_axis1 = array
1280 .mean_axis(Some(1))
1281 .expect("test: mean_axis(Some(1)) should succeed");
1282 assert_eq!(mean_axis1.shape(), vec![2]);
1283 assert_eq!(mean_axis1.to_vec(), vec![2.0, 5.0]);
1284
1285 let min_axis0 = array
1288 .min_axis(Some(0))
1289 .expect("test: min_axis(Some(0)) should succeed");
1290 assert_eq!(min_axis0.shape(), vec![3]);
1291 let min_axis0_vec = min_axis0.to_vec();
1293 assert_eq!(min_axis0_vec, vec![1.0, 2.0, 3.0]);
1294
1295 let min_axis1 = array
1297 .min_axis(Some(1))
1298 .expect("test: min_axis(Some(1)) should succeed");
1299 assert_eq!(min_axis1.shape(), vec![2]);
1300 assert_eq!(min_axis1.to_vec(), vec![1.0, 4.0]);
1302
1303 let max_axis1 = array
1305 .max_axis(Some(1))
1306 .expect("test: max_axis(Some(1)) should succeed");
1307 assert_eq!(max_axis1.shape(), vec![2]);
1308 assert_eq!(max_axis1.to_vec(), vec![3.0, 6.0]);
1310
1311 let mut array2 = Array::<f64>::zeros(&[2, 3]);
1313 array2
1314 .set(&[0, 0], 3.0)
1315 .expect("test: set array2[0,0] should succeed");
1316 array2
1317 .set(&[0, 1], 2.0)
1318 .expect("test: set array2[0,1] should succeed");
1319 array2
1320 .set(&[0, 2], 1.0)
1321 .expect("test: set array2[0,2] should succeed");
1322 array2
1323 .set(&[1, 0], 0.0)
1324 .expect("test: set array2[1,0] should succeed");
1325 array2
1326 .set(&[1, 1], 5.0)
1327 .expect("test: set array2[1,1] should succeed");
1328 array2
1329 .set(&[1, 2], 6.0)
1330 .expect("test: set array2[1,2] should succeed");
1331
1332 let argmin_axis0 = array2
1334 .argmin_axis(0)
1335 .expect("test: argmin_axis(0) should succeed");
1336 assert_eq!(argmin_axis0.shape(), vec![3]);
1337 assert_eq!(argmin_axis0.to_vec(), vec![1, 0, 0]);
1338
1339 let var_axis0 = array
1353 .var_axis(Some(0))
1354 .expect("test: var_axis(Some(0)) should succeed");
1355 assert_eq!(var_axis0.shape(), vec![3]);
1356 assert_relative_eq!(
1357 var_axis0
1358 .get(&[0])
1359 .expect("test: var_axis0 element access should succeed"),
1360 2.25,
1361 epsilon = 1e-10
1362 );
1363
1364 let std_axis1 = array
1366 .std_axis(Some(1))
1367 .expect("test: std_axis(Some(1)) should succeed");
1368 assert_eq!(std_axis1.shape(), vec![2]);
1369
1370 let std_row1 = std_axis1
1373 .get(&[0])
1374 .expect("test: std_axis1[0] access should succeed");
1375 assert!(
1376 std_row1 > 0.8 && std_row1 < 1.1,
1377 "std_row1 ({}) should be approximately 1.0 or 0.82",
1378 std_row1
1379 );
1380
1381 let std_row2 = std_axis1
1382 .get(&[1])
1383 .expect("test: std_axis1[1] access should succeed");
1384 assert!(
1385 std_row2 > 0.8 && std_row2 < 1.1,
1386 "std_row2 ({}) should be approximately 1.0 or 0.82",
1387 std_row2
1388 );
1389 }
1390
1391 #[test]
1392 fn test_views_and_strides() {
1393 use crate::views::SliceOrIndex;
1394
1395 let mut a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
1397 .reshape(&[3, 3]);
1398
1399 let view = a.view();
1401 assert_eq!(view.shape(), vec![3, 3]);
1402
1403 let mut view_mut = a.view_mut();
1405 view_mut
1406 .set(&[0, 0], 10.0)
1407 .expect("test: view_mut set should succeed");
1408 assert_eq!(
1409 a.get(&[0, 0])
1410 .expect("test: get after view_mut set should succeed"),
1411 10.0
1412 );
1413
1414 a.set(&[0, 0], 1.0)
1416 .expect("test: reset value should succeed");
1417
1418 let strided = a
1420 .strided_view(&[2, 2])
1421 .expect("test: strided_view should succeed");
1422 assert_eq!(strided.shape(), vec![2, 2]);
1423 let flat_data = strided.to_vec();
1424 assert!(flat_data.contains(&1.0));
1425 assert!(flat_data.contains(&3.0));
1426 assert!(flat_data.contains(&7.0));
1427 assert!(flat_data.contains(&9.0));
1428
1429 let slices = vec![
1431 SliceOrIndex::Slice(0, Some(2), None),
1432 SliceOrIndex::Slice(0, Some(2), None),
1433 ];
1434 let sliced = a
1435 .sliced_view(&slices)
1436 .expect("test: sliced_view should succeed");
1437 assert_eq!(sliced.shape(), vec![2, 2]);
1438 assert_eq!(sliced.to_vec(), vec![1.0, 2.0, 4.0, 5.0]);
1439
1440 let transposed = a.transposed_view();
1442 assert_eq!(transposed.shape(), vec![3, 3]);
1443 let _t_flat = transposed.to_vec();
1444 assert_eq!(
1446 transposed
1447 .get(&[0, 1])
1448 .expect("test: transposed get [0,1] should succeed"),
1449 4.0
1450 );
1451 assert_eq!(
1452 transposed
1453 .get(&[1, 0])
1454 .expect("test: transposed get [1,0] should succeed"),
1455 2.0
1456 );
1457
1458 let broadcast = a
1460 .broadcast_view(&[3, 3, 3])
1461 .expect("test: broadcast_view should succeed");
1462 assert_eq!(broadcast.shape(), vec![3, 3, 3]);
1463 assert_eq!(
1464 broadcast
1465 .get(&[0, 0, 0])
1466 .expect("test: broadcast get [0,0,0] should succeed"),
1467 1.0
1468 );
1469 assert_eq!(
1470 broadcast
1471 .get(&[1, 0, 0])
1472 .expect("test: broadcast get [1,0,0] should succeed"),
1473 1.0
1474 );
1475 }
1476
1477 #[test]
1478 fn test_universal_functions() {
1479 use crate::ufuncs::*;
1480
1481 let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
1483 let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]);
1484
1485 let result = add(&a, &b).expect("test: ufunc add should succeed");
1487 assert_eq!(result.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
1488
1489 let result = subtract(&a, &b).expect("test: ufunc subtract should succeed");
1490 assert_eq!(result.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
1491
1492 let result = multiply(&a, &b).expect("test: ufunc multiply should succeed");
1493 assert_eq!(result.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
1494
1495 let result = divide(&a, &b).expect("test: ufunc divide should succeed");
1496 assert_relative_eq!(result.to_vec()[0], 0.2, epsilon = 1e-10);
1497 assert_relative_eq!(result.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
1498 assert_relative_eq!(result.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
1499 assert_relative_eq!(result.to_vec()[3], 0.5, epsilon = 1e-10);
1500
1501 let result = power(&a, &b).expect("test: ufunc power should succeed");
1502 assert_relative_eq!(result.to_vec()[0], 1.0, epsilon = 1e-10);
1503 assert_relative_eq!(result.to_vec()[1], 64.0, epsilon = 1e-10);
1504 assert_relative_eq!(result.to_vec()[2], 2187.0, epsilon = 1e-10);
1505 assert_relative_eq!(result.to_vec()[3], 65536.0, epsilon = 1e-10);
1506
1507 let result = square(&a);
1509 assert_eq!(result.to_vec(), vec![1.0, 4.0, 9.0, 16.0]);
1510
1511 let result = sqrt(&a);
1512 assert_relative_eq!(result.to_vec()[0], 1.0, epsilon = 1e-10);
1513 assert_relative_eq!(
1514 result.to_vec()[1],
1515 std::f64::consts::SQRT_2,
1516 epsilon = 1e-10
1517 );
1518 assert_relative_eq!(result.to_vec()[2], 1.7320508075688772, epsilon = 1e-10);
1519 assert_relative_eq!(result.to_vec()[3], 2.0, epsilon = 1e-10);
1520
1521 let result = exp(&a);
1522 assert_relative_eq!(result.to_vec()[0], 1.0_f64.exp(), epsilon = 1e-10);
1523 assert_relative_eq!(result.to_vec()[1], 2.0_f64.exp(), epsilon = 1e-10);
1524 assert_relative_eq!(result.to_vec()[2], 3.0_f64.exp(), epsilon = 1e-10);
1525 assert_relative_eq!(result.to_vec()[3], 4.0_f64.exp(), epsilon = 1e-10);
1526
1527 let result = log(&a);
1528 assert_relative_eq!(result.to_vec()[0], 1.0_f64.ln(), epsilon = 1e-10);
1529 assert_relative_eq!(result.to_vec()[1], 2.0_f64.ln(), epsilon = 1e-10);
1530 assert_relative_eq!(result.to_vec()[2], 3.0_f64.ln(), epsilon = 1e-10);
1531 assert_relative_eq!(result.to_vec()[3], 4.0_f64.ln(), epsilon = 1e-10);
1532
1533 let result = multiply_scalar(&a, 2.0);
1535 assert_eq!(result.to_vec(), vec![2.0, 4.0, 6.0, 8.0]);
1536
1537 let row = Array::<f64>::from_vec(vec![10.0, 20.0]).reshape(&[1, 2]);
1539 let col = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[3, 1]);
1540 let result = add(&row, &col).expect("test: ufunc add with broadcasting should succeed");
1541 assert_eq!(result.shape(), vec![3, 2]);
1542 assert_eq!(result.to_vec(), vec![11.0, 21.0, 12.0, 22.0, 13.0, 23.0]);
1543 }
1544}