#![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;
pub mod array;
pub mod array_ops;
pub mod array_ops_legacy;
pub mod arrays;
#[cfg(feature = "arrow")]
pub mod arrow;
pub mod autodiff;
pub mod axis_ops;
pub mod bitwise_ops;
pub mod blas;
pub mod char;
pub mod cluster;
pub mod comparisons;
pub mod comparisons_broadcast;
pub mod complex_ops;
pub mod conversions;
pub mod derivative;
pub mod distance;
#[cfg(feature = "distributed")]
pub mod distributed;
pub mod error;
pub mod error_handling;
pub mod expr;
pub mod fft;
pub mod financial;
#[cfg(feature = "gpu")]
pub mod gpu;
pub mod indexing;
pub mod integrate;
pub mod interop;
pub mod interpolate;
pub mod io;
pub mod linalg;
pub mod linalg_accelerated;
pub mod linalg_extended;
pub mod linalg_optimized;
pub mod linalg_parallel;
pub mod optimized_ops; pub mod linalg_stable;
pub mod masked;
pub mod math;
pub mod math_extended;
pub mod matrix;
pub mod memory_alloc;
pub mod memory_optimize;
pub mod mmap;
pub mod ndimage;
pub mod nn;
pub mod ode;
pub mod optimize;
pub mod parallel;
pub mod parallel_optimize;
pub mod pde;
pub mod printing;
#[cfg(feature = "python")]
pub mod python;
pub mod random;
pub mod roots;
pub mod set_ops;
pub mod shared_array;
pub mod signal;
pub mod simd;
pub mod simd_optimize;
pub mod sparse;
pub mod sparse_enhanced;
pub mod spatial;
pub mod special;
pub mod stats;
pub mod stride_tricks;
pub mod symbolic;
pub mod testing;
pub mod traits;
pub mod types;
pub mod ufuncs;
pub mod unique;
pub mod unique_optimized;
pub mod util;
pub mod views;
#[cfg(feature = "visualization")]
pub mod viz;
#[cfg(feature = "wasm")]
pub mod wasm;
pub mod new_modules;
pub use error::{NumRs2Error, Result};
pub use random::random_base;
#[cfg(doctest)]
pub mod doctests {}
pub mod prelude {
pub use crate::array::Array;
pub use crate::array_ops::*;
pub use crate::array_ops_legacy::rollaxis;
pub use crate::axis_ops::*;
pub use crate::axis_ops::{apply_along_axis, apply_over_axes, vectorize};
pub use crate::bitwise_ops::{
bitwise_and, bitwise_not, bitwise_or, bitwise_xor, invert, left_shift, left_shift_scalar,
right_shift, right_shift_scalar,
};
pub use crate::char;
pub use crate::char::{array_from_strings, StringArray, StringElement};
pub use crate::comparisons::{
all, allclose, allclose_with_tol, any, array_equal, count_nonzero, equal, flatnonzero,
greater, greater_equal, isclose, isclose_array, less, less_equal, logical_and, logical_not,
logical_or, logical_xor, not_equal,
};
pub use crate::complex_ops::{
absolute as complex_abs, angle as complex_angle, conj as complex_conj, from_polar,
imag as complex_imag, iscomplex, iscomplexobj, isreal, isrealobj, real as complex_real,
to_complex,
};
pub use crate::conversions::*;
pub use crate::error::{NumRs2Error, Result};
pub use crate::error_handling::{
errstate, geterr, geterrcall, handle_error, seterr, seterrcall, ErrorAction, ErrorState,
ErrorStateBuilder, ErrorStateGuard, FloatingPointError,
};
pub use crate::financial::{
accrued_interest,
amortization_schedule,
binomial_option_price,
black_scholes,
black_scholes_greeks,
bond_convexity,
bond_duration,
bond_equivalent_yield,
bond_price,
bond_yield,
cumipmt,
cumprinc,
db,
ddb,
effect,
fv,
fv_array,
implied_volatility,
ipmt,
irr,
irr_multiple_series,
mirr,
modified_duration,
nominal,
nper,
nper_array,
npv,
npv_multiple_series,
npv_rates,
pmt,
pmt_array,
ppmt,
pv,
pv_array,
rate,
rate_array,
sln,
syd,
AmortizationSchedule,
};
pub use crate::indexing::{
diag_indices, diag_indices_from, extract, indices_grid, ix_, mask_indices,
put as indexing_put, put_along_axis, putmask as indexing_putmask, ravel_multi_index, take,
take_along_axis, tril_indices, tril_indices_from, triu_indices, triu_indices_from,
unravel_index, IndexSpec,
};
pub use crate::io::{array_to_vec2d, vec2d_to_array, vec_to_array, SerializeFormat};
#[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
pub use crate::linalg::{
cholesky as cholesky_basic, eig, inv, qr as qr_basic, solve, svd as svd_basic,
};
#[cfg(feature = "lapack")]
pub use crate::linalg::{det, matrix_power};
pub use crate::linalg::{inner, kron, norm, outer, tensordot, trace, vdot};
#[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
pub use crate::linalg::{matrix_rank, pinv};
pub use crate::linalg_extended::eigenvalue;
pub use crate::linalg_optimized::{lu_optimized, transpose_optimized, OptimizedBlas};
pub use crate::linalg_parallel::ParallelLinAlg;
pub use crate::linalg_stable::{
CholeskyStableResult, QRPivotedResult, SVDStableResult, StableDecompositions,
};
pub use crate::masked::MaskedArray;
pub use crate::ufuncs::{abs, ceil, exp, floor, log, round, sqrt};
pub use crate::math_extended::{erf, erfc, gamma, gammaln};
pub use crate::math::{
amax, amin, angle, arange, argmax, argmin, argpartition, argsort, around, bartlett,
bincount, blackman, clip, conj, copysign, cumprod, cumsum, cumulative_prod, cumulative_sum,
diff, diff_extended, digitize, divmod, ediff1d, empty, fmod, frexp, gcd, geomspace,
gradient, hamming, hanning, heaviside, i0, imag, interp, isfinite, isinf, isnan, kaiser,
lcm, ldexp, linspace, logspace, max, mean, median, min, modf, nan_to_num, nanmax, nanmean,
nanmin, nanstd, nansum, nanvar, nextafter, nonzero, ones, partition, prod, real,
real_if_close, remainder, resize, searchsorted, sinc, sort, std, sum, trapz, var, zeros,
ElementWiseMath,
};
pub use crate::matrix::{
asmatrix, matrix, matrix_from_nested, matrix_from_scalar, BandedMatrix, Matrix,
};
pub use crate::mmap::MmapArray;
pub use crate::random::advanced_distributions;
pub use crate::random::distributions;
pub use crate::random::generator::{default_rng, BitGenerator, Generator, StdBitGenerator};
pub use crate::random::{self, RandomState};
pub use crate::set_ops::{
in1d, intersect1d, isin, setdiff1d, setxor1d, union1d, unique_axis, unique_with_options,
};
pub use crate::signal::{convolve, convolve2d, correlate, correlate2d};
pub use crate::simd::get_simd_implementation_name;
pub use crate::sparse;
pub use crate::sparse_enhanced::SparseOpsAdvanced;
pub use crate::stats::{
average, corrcoef, cov, histogram, histogram_dd, max_along_axis, min_along_axis, mode,
percentile, ptp, quantile, HistBins, Statistics,
};
pub use crate::stride_tricks::{
as_strided, broadcast_arrays, broadcast_to, byte_strides, set_strides, sliding_window_view,
};
pub use crate::testing::{
arrays_close, assert_array_all_finite, assert_array_almost_equal, assert_array_equal,
assert_array_no_nan, assert_array_same_shape, assert_scalar_almost_equal, is_finite_array,
test_summary, tolerances, TestResult, ToleranceConfig,
};
pub use crate::run_tests;
pub use crate::traits::{
ArrayIndexing, ArrayMath, ArrayOps, ArrayReduction, ComplexElement, FloatingPoint,
IntegerElement, LinearAlgebra, MatrixDecomposition, NumericElement,
};
pub use crate::ufuncs::{
absolute, add, add_scalar, arctan2, cbrt, divide, divide_scalar, dot, exp2, expm1, fma,
hypot, log10, log1p, log2, maximum, minimum, multiply, multiply_scalar, negative, norm_l1,
norm_l2, power, power_scalar, reciprocal, subtract, subtract_scalar, BinaryUfunc,
UnaryUfunc,
};
pub use crate::unique::{unique, UniqueResult};
pub use crate::unique_optimized::unique_optimized;
pub use crate::util::{
astype, can_operate_inplace, fast_sum, optimize_layout, parallel_map, MemoryLayout,
};
pub use crate::views::*;
pub use crate::interop::ndarray_compat::{from_ndarray, to_ndarray};
pub use crate::memory_optimize::{
align_data, optimize_layout as memory_optimize_layout, optimize_placement,
AlignmentStrategy, LayoutStrategy, PlacementStrategy,
};
pub use crate::parallel_optimize::{
adaptive_threshold, optimize_parallel_computation, optimize_scheduling, partition_workload,
};
pub use crate::parallel_optimize::{
ParallelConfig, ParallelizationThreshold, SchedulingStrategy, WorkloadPartitioning,
};
pub use crate::printing::{
array_str, get_printoptions, reset_printoptions, set_printoptions, PrintOptions,
};
pub use crate::memory_alloc::{
get_default_allocator, get_global_allocator_strategy, init_global_allocator,
reset_global_allocator,
};
pub use crate::memory_alloc::{
AlignedAllocator, AlignmentConfig, AllocStrategy, ArenaAllocator, ArenaConfig, CacheConfig,
CacheLevel, CacheOptimizedAllocator, PoolAllocator, PoolConfig,
};
pub use crate::algorithms::{
BandwidthEstimate, BandwidthOptimizer, CacheAwareArrayOps, CacheAwareConvolution,
CacheAwareFFT, MemoryOperation,
};
pub use crate::parallel::parallel_algorithms::ParallelConfig as ParallelAlgorithmConfig;
pub use crate::parallel::{
global_parallel_context, initialize_parallel_context, shutdown_parallel_context, task,
BalancingStrategy, LoadBalancer, ParallelAllocator, ParallelAllocatorConfig,
ParallelArrayOps, ParallelContext, ParallelFFT, ParallelMatrixOps, ParallelScheduler,
SchedulerConfig, Task, TaskPriority, TaskResult, ThreadLocalAllocator, WorkStealingPool,
WorkloadMetrics,
};
pub use crate::memory_alloc::{
EnhancedAllocatorBridge, IntelligentAllocationStrategy, NumericalArrayAllocator,
};
pub use crate::traits::{
AllocationFrequency, AllocationLifetime, AllocationRequirements, AllocationStats,
AllocationStrategy, MemoryAllocator, MemoryAware, MemoryOptimization, MemoryUsage,
OptimizationType, SpecializedAllocator, ThreadingRequirements,
};
#[cfg(feature = "lapack")]
pub use crate::new_modules::eigenvalues::{eig as eig_general, eigh, eigvals, eigvalsh};
pub use crate::new_modules::fft::FFT;
#[cfg(all(feature = "matrix_decomp", feature = "lapack"))]
pub use crate::new_modules::matrix_decomp::{
cholesky, cod, condition_number, lu, pivoted_cholesky, qr, rcond, schur, svd,
};
pub use crate::new_modules::polynomial::{
poly, polyadd, polychebyshev, polycompanion, polycompose, polyder, polydiv, polyextrap,
polyfit, polyfit_weighted, polyfromroots, polygcd, polygrid2d, polyhermite, polyint,
polyjacobi, polylaguerre, polylegendre, polymul, polymulx, polypower, polyresidual,
polyscale, polysub, polytrim, polyval2d, polyvander, polyvander2d, CubicSpline, Polynomial,
PolynomialInterpolation,
};
#[cfg(feature = "lapack")]
pub use crate::optimized_ops::parallel_matrix_ops;
pub use crate::optimized_ops::{
adaptive_array_sum, chunked_array_processing, get_optimization_info,
parallel_column_statistics, should_use_parallel, simd_elementwise_ops, simd_matmul,
simd_vector_ops, ColumnStats, SimdOpsResult, SimdVectorResult,
};
#[cfg(feature = "gpu")]
pub use crate::gpu::{
add as gpu_add, divide as gpu_divide, matmul, multiply as gpu_multiply,
subtract as gpu_subtract, transpose, GpuArray, GpuContext,
};
pub use crate::new_modules::sparse::{SparseArray, SparseMatrix, SparseMatrixFormat};
pub use crate::new_modules::special::{
airy_ai, airy_bi, associated_legendre_p, bessel_i, bessel_j, bessel_k, bessel_y, beta,
betainc, digamma, ellipe, ellipeinc, ellipf, ellipk, erfcinv, erfinv, exp1, expi, fresnel,
gammainc, jacobi_elliptic, lambertw, lambertwm1, legendre_p, polylog, shichi, sici,
spherical_harmonic, struve_h, zeta,
};
pub use crate::arrays::{
ArrayView, BooleanCombineOp, BroadcastEngine, BroadcastOp, BroadcastReduction,
FancyIndexEngine, FancyIndexResult, ResolvedIndex, Shape, SpecializedIndexing,
};
pub use crate::types::custom::CustomDType;
pub use crate::types::datetime::{
business_days,
datetime64,
datetime_array,
datetime_as_string,
datetime_data,
timedelta64,
DateTime64,
DateTimeUnit,
DateUnit,
TimeDelta64,
Timezone,
TimezoneDateTime,
};
pub use crate::types::structured::{DType, Field, RecordArray, StructuredArray};
pub use crate::shared_array::{SharedArray, SharedArrayView};
pub use crate::expr::{
ArrayExpr,
BinaryExpr,
CSEOptimizer,
CSESupport,
CachedExpr,
Expr,
ExprBuilder,
ExprCache,
ExprId,
ExprKey,
LazyEval,
ScalarExpr,
SharedArrayExpr,
SharedBinaryExpr,
SharedExpr,
SharedExprBuilder,
SharedScalarExpr,
SharedUnaryExpr,
UnaryExpr,
};
pub use crate::memory_optimize::access_patterns::{
cache_aware_binary_op, cache_aware_copy, cache_aware_transform, detect_layout,
AccessPattern, AccessStats, Block, BlockedIterator, OptimizationHints, StrideOptimizer,
Tile2D, TiledIterator2D,
};
pub use scirs2_core::ndarray::{Axis, Dimension, IxDyn, ShapeBuilder};
pub use scirs2_core::{Complex, Complex64};
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::simd::{simd_add, simd_div, simd_mul, simd_prod, simd_sqrt, simd_sum};
use approx::assert_relative_eq;
#[test]
fn basic_array_ops() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
let c = a.add(&b);
assert_eq!(c.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
let d = a.subtract(&b);
assert_eq!(d.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
let e = a.multiply(&b);
assert_eq!(e.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
let f = a.divide(&b);
assert_relative_eq!(f.to_vec()[0], 0.2, epsilon = 1e-10);
assert_relative_eq!(f.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
assert_relative_eq!(f.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
assert_relative_eq!(f.to_vec()[3], 0.5, epsilon = 1e-10);
}
#[test]
fn test_broadcasting() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let b = a.add_scalar(5.0);
assert_eq!(b.to_vec(), vec![6.0, 7.0, 8.0]);
let c = a.multiply_scalar(2.0);
assert_eq!(c.to_vec(), vec![2.0, 4.0, 6.0]);
let row = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[1, 3]);
let col = Array::<f64>::from_vec(vec![4.0, 5.0]).reshape(&[2, 1]);
let result = row
.add_broadcast(&col)
.expect("test: broadcast addition should succeed");
assert_eq!(result.shape(), vec![2, 3]);
assert_eq!(result.to_vec(), vec![5.0, 6.0, 7.0, 6.0, 7.0, 8.0]);
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let b = Array::<f64>::from_vec(vec![10.0, 20.0]).reshape(&[1, 2]);
let result = a
.multiply_broadcast(&b)
.expect("test: broadcast multiplication should succeed");
assert_eq!(result.shape(), vec![2, 2]);
assert_eq!(result.to_vec(), vec![10.0, 40.0, 30.0, 80.0]);
let shape1 = vec![3, 1, 4];
let shape2 = vec![2, 1];
let broadcast_shape = Array::<f64>::broadcast_shape(&shape1, &shape2)
.expect("test: broadcast shape computation should succeed");
assert_eq!(broadcast_shape, vec![3, 2, 4]);
}
#[test]
fn test_array_creation() {
let zeros = Array::<f64>::zeros(&[2, 3]);
assert_eq!(zeros.shape(), vec![2, 3]);
assert_eq!(zeros.to_vec(), vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
let ones = Array::<f64>::ones(&[2, 2]);
assert_eq!(ones.shape(), vec![2, 2]);
assert_eq!(ones.to_vec(), vec![1.0, 1.0, 1.0, 1.0]);
let fives = Array::<f64>::full(&[2, 2], 5.0);
assert_eq!(fives.shape(), vec![2, 2]);
assert_eq!(fives.to_vec(), vec![5.0, 5.0, 5.0, 5.0]);
let arr = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let reshaped = arr.reshape(&[2, 3]);
assert_eq!(reshaped.shape(), vec![2, 3]);
assert_eq!(reshaped.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
}
#[test]
fn test_array_methods() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).reshape(&[2, 3]);
assert_eq!(a.shape(), vec![2, 3]);
assert_eq!(a.ndim(), 2);
assert_eq!(a.size(), 6);
let at = a.transpose();
assert_eq!(at.shape(), vec![3, 2]);
let at_vec = at.to_vec();
assert_eq!(at_vec.len(), 6);
assert!(at_vec.contains(&1.0));
assert!(at_vec.contains(&2.0));
assert!(at_vec.contains(&3.0));
assert!(at_vec.contains(&4.0));
assert!(at_vec.contains(&5.0));
assert!(at_vec.contains(&6.0));
let slice = a
.slice(0, 1)
.expect("test: slice should succeed for valid axis");
assert_eq!(slice.shape(), vec![3]);
assert_eq!(slice.to_vec(), vec![4.0, 5.0, 6.0]);
}
#[test]
fn test_map_operations() {
let a = Array::<f64>::from_vec(vec![1.0, 4.0, 9.0, 16.0]);
let sqrt_a = a.map(|x| x.sqrt());
assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
let par_sqrt_a = a.par_map(|x| x.sqrt());
assert_relative_eq!(par_sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(par_sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
assert_relative_eq!(par_sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
assert_relative_eq!(par_sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
}
#[cfg(feature = "lapack")]
#[test]
fn test_linalg_ops() {
let a = Array::<f64>::from_vec(vec![4.0, 7.0, 2.0, 6.0]).reshape(&[2, 2]);
let det_a = det(&a).expect("test: determinant computation should succeed");
assert_relative_eq!(det_a, 10.0, epsilon = 1e-10);
let inv_a = inv(&a).expect("test: matrix inverse should succeed for invertible matrix");
let expected_inv = [0.6, -0.7, -0.2, 0.4];
for (actual, expected) in inv_a.to_vec().iter().zip(expected_inv.iter()) {
assert_relative_eq!(*actual, *expected, epsilon = 1e-10);
}
let identity = a
.matmul(&inv_a)
.expect("test: matrix multiplication should succeed");
assert_relative_eq!(identity.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(identity.to_vec()[1], 0.0, epsilon = 1e-10);
assert_relative_eq!(identity.to_vec()[2], 0.0, epsilon = 1e-10);
assert_relative_eq!(identity.to_vec()[3], 1.0, epsilon = 1e-10);
let b = Array::<f64>::from_vec(vec![1.0, 3.0]);
let x = solve(&a, &b).expect("test: linear system solve should succeed");
assert_relative_eq!(x.to_vec()[0], -1.5, epsilon = 1e-10);
assert_relative_eq!(x.to_vec()[1], 1.0, epsilon = 1e-10);
let b_check = a
.matmul(&x.reshape(&[2, 1]))
.expect("test: matrix-vector multiplication should succeed")
.reshape(&[2]);
assert_relative_eq!(b_check.to_vec()[0], b.to_vec()[0], epsilon = 1e-10);
assert_relative_eq!(b_check.to_vec()[1], b.to_vec()[1], epsilon = 1e-10);
}
#[test]
fn test_tensor_operations() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0]).reshape(&[1, 2]);
let b = Array::<f64>::from_vec(vec![3.0, 4.0]).reshape(&[2, 1]);
let kron_result = kron(&a, &b).expect("test: Kronecker product should succeed");
assert_eq!(kron_result.shape(), &[2, 2]);
assert_eq!(kron_result.to_vec(), vec![3.0, 6.0, 4.0, 8.0]);
let tensordot_result = tensordot(&a, &b, &[1, 0]).expect("test: tensordot should succeed");
assert_eq!(tensordot_result.shape(), &[1, 1]);
assert_relative_eq!(tensordot_result.to_vec()[0], 11.0, epsilon = 1e-10);
}
#[test]
fn test_matrix_operations() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
let c = a
.matmul(&b)
.expect("test: matrix multiplication should succeed");
assert_eq!(c.shape(), vec![2, 2]);
assert_eq!(c.to_vec(), vec![19.0, 22.0, 43.0, 50.0]);
let v = Array::<f64>::from_vec(vec![1.0, 2.0]);
let result = a
.matmul(&v.reshape(&[2, 1]))
.expect("test: matrix-vector multiplication should succeed")
.reshape(&[2]);
assert_eq!(result.to_vec(), vec![5.0, 11.0]);
}
#[test]
fn test_simd_operations() {
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]);
let c = simd_add(&a, &b).expect("test: SIMD addition should succeed");
assert_eq!(c.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
let d = simd_mul(&a, &b).expect("test: SIMD multiplication should succeed");
assert_eq!(d.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
let e = simd_div(&a, &b).expect("test: SIMD division should succeed");
assert_relative_eq!(e.to_vec()[0], 0.2, epsilon = 1e-10);
assert_relative_eq!(e.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
assert_relative_eq!(e.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
assert_relative_eq!(e.to_vec()[3], 0.5, epsilon = 1e-10);
let sqrt_a = simd_sqrt(&a);
assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(
sqrt_a.to_vec()[1],
std::f64::consts::SQRT_2,
epsilon = 1e-10
);
assert_relative_eq!(sqrt_a.to_vec()[2], 1.7320508075688772, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[3], 2.0, epsilon = 1e-10);
assert_eq!(simd_sum(&a), 10.0);
assert_eq!(simd_prod(&a), 24.0);
}
#[test]
fn test_norm_functions() {
let v = Array::<f64>::from_vec(vec![3.0, 4.0]);
let norm_1 = norm(&v, Some(1.0)).expect("test: L1 norm computation should succeed");
assert_relative_eq!(norm_1, 7.0, epsilon = 1e-10);
let norm_2 = norm(&v, Some(2.0)).expect("test: L2 norm computation should succeed");
assert_relative_eq!(norm_2, 5.0, epsilon = 1e-10);
let norm_inf =
norm(&v, Some(f64::INFINITY)).expect("test: infinity norm computation should succeed");
assert_relative_eq!(norm_inf, 4.0, epsilon = 1e-10);
let m = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let matrix_norm_1 =
norm(&m, Some(1.0)).expect("test: matrix L1 norm computation should succeed");
assert_relative_eq!(matrix_norm_1, 6.0, epsilon = 1e-10);
let matrix_norm_inf = norm(&m, Some(f64::INFINITY))
.expect("test: matrix infinity norm computation should succeed");
assert_relative_eq!(matrix_norm_inf, 7.0, epsilon = 1e-10);
}
#[test]
fn test_math_operations() {
use crate::math::*;
let a = Array::<f64>::from_vec(vec![1.0, 4.0, 9.0, 16.0]);
let neg_a = a.map(|x| -x);
let abs_a = neg_a.abs();
for (expected, actual) in a.to_vec().iter().zip(abs_a.to_vec().iter()) {
assert_relative_eq!(*expected, *actual, epsilon = 1e-10);
}
let exp_a = a.exp();
assert_relative_eq!(exp_a.to_vec()[0], 1.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(exp_a.to_vec()[1], 4.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(exp_a.to_vec()[2], 9.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(exp_a.to_vec()[3], 16.0_f64.exp(), epsilon = 1e-10);
let log_a = a.log();
assert_relative_eq!(log_a.to_vec()[0], 1.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(log_a.to_vec()[1], 4.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(log_a.to_vec()[2], 9.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(log_a.to_vec()[3], 16.0_f64.ln(), epsilon = 1e-10);
let sqrt_a = a.sqrt();
assert_relative_eq!(sqrt_a.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[1], 2.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[2], 3.0, epsilon = 1e-10);
assert_relative_eq!(sqrt_a.to_vec()[3], 4.0, epsilon = 1e-10);
let pow_a = a.pow(2.0);
assert_relative_eq!(pow_a.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(pow_a.to_vec()[1], 16.0, epsilon = 1e-10);
assert_relative_eq!(pow_a.to_vec()[2], 81.0, epsilon = 1e-10);
assert_relative_eq!(pow_a.to_vec()[3], 256.0, epsilon = 1e-10);
let angles = Array::<f64>::from_vec(vec![
0.0,
std::f64::consts::PI / 6.0,
std::f64::consts::PI / 4.0,
std::f64::consts::PI / 3.0,
]);
let sin_angles = angles.sin();
assert_relative_eq!(sin_angles.to_vec()[0], 0.0, epsilon = 1e-10);
assert_relative_eq!(sin_angles.to_vec()[1], 0.5, epsilon = 1e-10);
assert_relative_eq!(
sin_angles.to_vec()[2],
1.0 / std::f64::consts::SQRT_2,
epsilon = 1e-10
);
assert_relative_eq!(sin_angles.to_vec()[3], 0.8660254037844386, epsilon = 1e-10);
let cos_angles = angles.cos();
assert_relative_eq!(cos_angles.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(cos_angles.to_vec()[1], 0.8660254037844386, epsilon = 1e-10);
assert_relative_eq!(
cos_angles.to_vec()[2],
1.0 / std::f64::consts::SQRT_2,
epsilon = 1e-10
);
assert_relative_eq!(cos_angles.to_vec()[3], 0.5, epsilon = 1e-10);
let lin = linspace(0.0, 10.0, 6);
assert_eq!(lin.size(), 6);
assert_relative_eq!(lin.to_vec()[0], 0.0, epsilon = 1e-10);
assert_relative_eq!(lin.to_vec()[1], 2.0, epsilon = 1e-10);
assert_relative_eq!(lin.to_vec()[2], 4.0, epsilon = 1e-10);
assert_relative_eq!(lin.to_vec()[3], 6.0, epsilon = 1e-10);
assert_relative_eq!(lin.to_vec()[4], 8.0, epsilon = 1e-10);
assert_relative_eq!(lin.to_vec()[5], 10.0, epsilon = 1e-10);
let range = arange(0.0, 5.0, 1.0);
assert_eq!(range.size(), 5);
assert_eq!(range.to_vec(), vec![0.0, 1.0, 2.0, 3.0, 4.0]);
let rev_range = arange(5.0, 0.0, -1.0);
assert_eq!(rev_range.size(), 5);
assert_eq!(rev_range.to_vec(), vec![5.0, 4.0, 3.0, 2.0, 1.0]);
let log_space = logspace(0.0, 3.0, 4, None);
assert_eq!(log_space.size(), 4);
assert_relative_eq!(log_space.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(log_space.to_vec()[1], 10.0, epsilon = 1e-10);
assert_relative_eq!(log_space.to_vec()[2], 100.0, epsilon = 1e-10);
assert_relative_eq!(log_space.to_vec()[3], 1000.0, epsilon = 1e-10);
let geom_space = geomspace(1.0, 1000.0, 4);
assert_eq!(geom_space.size(), 4);
assert_relative_eq!(geom_space.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(geom_space.to_vec()[1], 10.0, epsilon = 1e-10);
assert_relative_eq!(geom_space.to_vec()[2], 100.0, epsilon = 1e-10);
assert_relative_eq!(geom_space.to_vec()[3], 1000.0, epsilon = 1e-10);
}
#[test]
fn test_array_operations() {
use crate::array_ops::*;
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let tiled = tile(&a, &[2]).expect("test: tile operation should succeed");
assert_eq!(tiled.shape(), vec![6]);
assert_eq!(tiled.to_vec(), vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let tiled_2d = tile(&a_2d, &[2, 1]).expect("test: 2D tile operation should succeed");
assert_eq!(tiled_2d.shape(), vec![4, 2]);
assert_eq!(
tiled_2d.to_vec(),
vec![1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0]
);
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let repeated = repeat(&a, 2, None).expect("test: repeat operation should succeed");
assert_eq!(repeated.shape(), vec![6]);
assert_eq!(repeated.to_vec(), vec![1.0, 1.0, 2.0, 2.0, 3.0, 3.0]);
let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let repeated_axis0 =
repeat(&a_2d, 2, Some(0)).expect("test: repeat along axis 0 should succeed");
assert_eq!(repeated_axis0.shape(), vec![4, 2]);
assert_eq!(
repeated_axis0.to_vec(),
vec![1.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 4.0]
);
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let b = Array::<f64>::from_vec(vec![4.0, 5.0, 6.0]);
let c = concatenate(&[&a, &b], 0).expect("test: concatenate should succeed");
assert_eq!(c.shape(), vec![6]);
assert_eq!(c.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]).reshape(&[2, 2]);
let b_2d = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]).reshape(&[2, 2]);
let c_axis0 =
concatenate(&[&a_2d, &b_2d], 0).expect("test: concatenate along axis 0 should succeed");
assert_eq!(c_axis0.shape(), vec![4, 2]);
assert_eq!(
c_axis0.to_vec(),
vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
);
let c_axis1 =
concatenate(&[&a_2d, &b_2d], 1).expect("test: concatenate along axis 1 should succeed");
assert_eq!(c_axis1.shape(), vec![2, 4]);
let c_vec = c_axis1.to_vec();
assert_eq!(c_vec.len(), 8);
assert!(c_vec.contains(&1.0));
assert!(c_vec.contains(&2.0));
assert!(c_vec.contains(&3.0));
assert!(c_vec.contains(&4.0));
assert!(c_vec.contains(&5.0));
assert!(c_vec.contains(&6.0));
assert!(c_vec.contains(&7.0));
assert!(c_vec.contains(&8.0));
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let b = Array::<f64>::from_vec(vec![4.0, 5.0, 6.0]);
let c = stack(&[&a, &b], 0).expect("test: stack along axis 0 should succeed");
assert_eq!(c.shape(), vec![2, 3]);
let c_vec = c.to_vec();
assert_eq!(c_vec.len(), 6);
assert!(c_vec.contains(&1.0));
assert!(c_vec.contains(&2.0));
assert!(c_vec.contains(&3.0));
assert!(c_vec.contains(&4.0));
assert!(c_vec.contains(&5.0));
assert!(c_vec.contains(&6.0));
let d = stack(&[&a, &b], 1).expect("test: stack along axis 1 should succeed");
assert_eq!(d.shape(), vec![3, 2]);
let d_vec = d.to_vec();
assert_eq!(d_vec.len(), 6);
assert!(d_vec.contains(&1.0));
assert!(d_vec.contains(&2.0));
assert!(d_vec.contains(&3.0));
assert!(d_vec.contains(&4.0));
assert!(d_vec.contains(&5.0));
assert!(d_vec.contains(&6.0));
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let splits = split(&a, &[2, 4], 0).expect("test: split should succeed");
assert_eq!(splits.len(), 3);
assert_eq!(splits[0].to_vec(), vec![1.0, 2.0]);
assert_eq!(splits[1].to_vec(), vec![3.0, 4.0]);
assert_eq!(splits[2].to_vec(), vec![5.0, 6.0]);
let _a_2d = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).reshape(&[2, 3]);
let splits_a =
split(&a, &[2, 4], 0).expect("test: split with multiple indices should succeed");
assert_eq!(splits_a.len(), 3);
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]);
let expanded = expand_dims(&a, 0).expect("test: expand_dims should succeed");
assert_eq!(expanded.shape(), vec![1, 3]);
assert_eq!(expanded.to_vec(), vec![1.0, 2.0, 3.0]);
let expanded_end = expand_dims(&a, 1).expect("test: expand_dims at end should succeed");
assert_eq!(expanded_end.shape(), vec![3, 1]);
assert_eq!(expanded_end.to_vec(), vec![1.0, 2.0, 3.0]);
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[1, 3, 1]);
let squeezed = squeeze(&a, None).expect("test: squeeze should succeed");
assert_eq!(squeezed.shape(), vec![3]);
assert_eq!(squeezed.to_vec(), vec![1.0, 2.0, 3.0]);
let squeezed_axis = squeeze(&a, Some(0)).expect("test: squeeze at axis 0 should succeed");
assert_eq!(squeezed_axis.shape(), vec![3, 1]);
assert_eq!(squeezed_axis.to_vec(), vec![1.0, 2.0, 3.0]);
}
#[test]
fn test_statistics_functions() {
use crate::stats::*;
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
assert_relative_eq!(a.mean(), 3.0, epsilon = 1e-10);
assert_relative_eq!(a.var(), 2.0, epsilon = 1e-10);
assert_relative_eq!(a.std(), std::f64::consts::SQRT_2, epsilon = 1e-10);
assert_relative_eq!(a.min(), 1.0, epsilon = 1e-10);
assert_relative_eq!(a.max(), 5.0, epsilon = 1e-10);
assert_relative_eq!(a.percentile(0.0), 1.0, epsilon = 1e-10);
assert_relative_eq!(a.percentile(0.5), 3.0, epsilon = 1e-10);
assert_relative_eq!(a.percentile(1.0), 5.0, epsilon = 1e-10);
assert_relative_eq!(a.percentile(0.25), 2.0, epsilon = 1e-10);
assert_relative_eq!(a.percentile(0.75), 4.0, epsilon = 1e-10);
let b = Array::<f64>::from_vec(vec![5.0, 4.0, 3.0, 2.0, 1.0]);
let cov_result =
cov(&a, Some(&b), None, None, None).expect("test: covariance should succeed");
assert_relative_eq!(
cov_result
.get(&[0, 1])
.expect("test: cov element access should succeed"),
-2.5,
epsilon = 1e-10
);
let corrcoef_result =
corrcoef(&a, Some(&b), None).expect("test: correlation coefficient should succeed");
assert_relative_eq!(
corrcoef_result
.get(&[0, 1])
.expect("test: corrcoef element access should succeed"),
-1.0,
epsilon = 1e-10
);
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]);
let (counts, bins) =
histogram(&data, 4, None, None).expect("test: histogram should succeed");
assert_eq!(counts.to_vec(), vec![2.0, 2.0, 2.0, 3.0]);
assert_eq!(bins.size(), 5);
assert_relative_eq!(bins.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(bins.to_vec()[4], 5.0, epsilon = 1e-10);
}
#[test]
fn test_boolean_indexing() {
use crate::indexing::*;
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0]);
let mask = vec![true, false, true, false, true];
let _bool_array = Array::<bool>::from_vec(mask.clone());
let mut filtered = Array::<f64>::zeros(&[5]);
let values = Array::<f64>::from_vec(vec![1.0, 3.0, 5.0]);
let mut value_idx = 0;
for (i, &m) in mask.iter().enumerate() {
if m {
filtered
.set(
&[i],
values
.get(&[value_idx])
.expect("test: value access should succeed"),
)
.expect("test: set filtered value should succeed");
value_idx += 1;
}
}
assert_eq!(filtered.to_vec(), vec![1.0, 0.0, 3.0, 0.0, 5.0]);
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])
.reshape(&[3, 3]);
let _row_indices = [0]; let _col_indices = [0];
let row_result = a_2d
.index(&[IndexSpec::Index(0), IndexSpec::All])
.expect("test: row indexing should succeed");
assert_eq!(row_result.shape(), vec![3]);
let row_vec = row_result.to_vec();
assert_eq!(row_vec.len(), 3);
assert_eq!(row_vec, vec![1.0, 2.0, 3.0]);
let col_result = a_2d
.index(&[IndexSpec::All, IndexSpec::Index(0)])
.expect("test: column indexing should succeed");
assert_eq!(col_result.shape(), vec![3]); assert_eq!(col_result.to_vec(), vec![1.0, 4.0, 7.0]);
let mut a_copy = a.clone();
a_copy
.set_mask(
&Array::<bool>::from_vec(vec![true, false, true, false, true]),
&Array::<f64>::from_vec(vec![10.0, 30.0, 50.0]),
)
.expect("test: set_mask should succeed");
assert_eq!(a_copy.to_vec(), vec![10.0, 2.0, 30.0, 4.0, 50.0]);
}
#[test]
fn test_fancy_indexing() {
use crate::indexing::*;
let _a = Array::<f64>::from_vec(vec![10.0, 20.0, 30.0, 40.0, 50.0]);
let _indices = [0, 1, 2];
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])
.reshape(&[3, 3]);
let single_element = a_2d
.index(&[IndexSpec::Index(1), IndexSpec::Index(1)])
.expect("test: single element indexing should succeed");
assert_eq!(single_element.to_vec(), vec![5.0]);
let slice_result = a_2d
.index(&[IndexSpec::Slice(0, Some(2), None), IndexSpec::All])
.expect("test: slice indexing should succeed");
assert_eq!(slice_result.shape(), vec![2, 3]);
assert_eq!(slice_result.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
}
#[test]
fn test_axis_operations() {
use crate::axis_ops::*;
let mut array = Array::<f64>::zeros(&[2, 3]);
array
.set(&[0, 0], 1.0)
.expect("test: set [0,0] should succeed");
array
.set(&[0, 1], 2.0)
.expect("test: set [0,1] should succeed");
array
.set(&[0, 2], 3.0)
.expect("test: set [0,2] should succeed");
array
.set(&[1, 0], 4.0)
.expect("test: set [1,0] should succeed");
array
.set(&[1, 1], 5.0)
.expect("test: set [1,1] should succeed");
array
.set(&[1, 2], 6.0)
.expect("test: set [1,2] should succeed");
let sum_axis0 = array.sum_axis(0).expect("test: sum_axis(0) should succeed");
assert_eq!(sum_axis0.shape(), vec![3]);
assert_eq!(sum_axis0.to_vec(), vec![5.0, 7.0, 9.0]);
let sum_axis1 = array.sum_axis(1).expect("test: sum_axis(1) should succeed");
assert_eq!(sum_axis1.shape(), vec![2]);
assert_eq!(sum_axis1.to_vec(), vec![6.0, 15.0]);
let mean_axis0 = array
.mean_axis(Some(0))
.expect("test: mean_axis(Some(0)) should succeed");
assert_eq!(mean_axis0.shape(), vec![3]);
assert_eq!(mean_axis0.to_vec(), vec![2.5, 3.5, 4.5]);
let mean_axis1 = array
.mean_axis(Some(1))
.expect("test: mean_axis(Some(1)) should succeed");
assert_eq!(mean_axis1.shape(), vec![2]);
assert_eq!(mean_axis1.to_vec(), vec![2.0, 5.0]);
let min_axis0 = array
.min_axis(Some(0))
.expect("test: min_axis(Some(0)) should succeed");
assert_eq!(min_axis0.shape(), vec![3]);
let min_axis0_vec = min_axis0.to_vec();
assert_eq!(min_axis0_vec, vec![1.0, 2.0, 3.0]);
let min_axis1 = array
.min_axis(Some(1))
.expect("test: min_axis(Some(1)) should succeed");
assert_eq!(min_axis1.shape(), vec![2]);
assert_eq!(min_axis1.to_vec(), vec![1.0, 4.0]);
let max_axis1 = array
.max_axis(Some(1))
.expect("test: max_axis(Some(1)) should succeed");
assert_eq!(max_axis1.shape(), vec![2]);
assert_eq!(max_axis1.to_vec(), vec![3.0, 6.0]);
let mut array2 = Array::<f64>::zeros(&[2, 3]);
array2
.set(&[0, 0], 3.0)
.expect("test: set array2[0,0] should succeed");
array2
.set(&[0, 1], 2.0)
.expect("test: set array2[0,1] should succeed");
array2
.set(&[0, 2], 1.0)
.expect("test: set array2[0,2] should succeed");
array2
.set(&[1, 0], 0.0)
.expect("test: set array2[1,0] should succeed");
array2
.set(&[1, 1], 5.0)
.expect("test: set array2[1,1] should succeed");
array2
.set(&[1, 2], 6.0)
.expect("test: set array2[1,2] should succeed");
let argmin_axis0 = array2
.argmin_axis(0)
.expect("test: argmin_axis(0) should succeed");
assert_eq!(argmin_axis0.shape(), vec![3]);
assert_eq!(argmin_axis0.to_vec(), vec![1, 0, 0]);
let var_axis0 = array
.var_axis(Some(0))
.expect("test: var_axis(Some(0)) should succeed");
assert_eq!(var_axis0.shape(), vec![3]);
assert_relative_eq!(
var_axis0
.get(&[0])
.expect("test: var_axis0 element access should succeed"),
2.25,
epsilon = 1e-10
);
let std_axis1 = array
.std_axis(Some(1))
.expect("test: std_axis(Some(1)) should succeed");
assert_eq!(std_axis1.shape(), vec![2]);
let std_row1 = std_axis1
.get(&[0])
.expect("test: std_axis1[0] access should succeed");
assert!(
std_row1 > 0.8 && std_row1 < 1.1,
"std_row1 ({}) should be approximately 1.0 or 0.82",
std_row1
);
let std_row2 = std_axis1
.get(&[1])
.expect("test: std_axis1[1] access should succeed");
assert!(
std_row2 > 0.8 && std_row2 < 1.1,
"std_row2 ({}) should be approximately 1.0 or 0.82",
std_row2
);
}
#[test]
fn test_views_and_strides() {
use crate::views::SliceOrIndex;
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])
.reshape(&[3, 3]);
let view = a.view();
assert_eq!(view.shape(), vec![3, 3]);
let mut view_mut = a.view_mut();
view_mut
.set(&[0, 0], 10.0)
.expect("test: view_mut set should succeed");
assert_eq!(
a.get(&[0, 0])
.expect("test: get after view_mut set should succeed"),
10.0
);
a.set(&[0, 0], 1.0)
.expect("test: reset value should succeed");
let strided = a
.strided_view(&[2, 2])
.expect("test: strided_view should succeed");
assert_eq!(strided.shape(), vec![2, 2]);
let flat_data = strided.to_vec();
assert!(flat_data.contains(&1.0));
assert!(flat_data.contains(&3.0));
assert!(flat_data.contains(&7.0));
assert!(flat_data.contains(&9.0));
let slices = vec![
SliceOrIndex::Slice(0, Some(2), None),
SliceOrIndex::Slice(0, Some(2), None),
];
let sliced = a
.sliced_view(&slices)
.expect("test: sliced_view should succeed");
assert_eq!(sliced.shape(), vec![2, 2]);
assert_eq!(sliced.to_vec(), vec![1.0, 2.0, 4.0, 5.0]);
let transposed = a.transposed_view();
assert_eq!(transposed.shape(), vec![3, 3]);
let _t_flat = transposed.to_vec();
assert_eq!(
transposed
.get(&[0, 1])
.expect("test: transposed get [0,1] should succeed"),
4.0
);
assert_eq!(
transposed
.get(&[1, 0])
.expect("test: transposed get [1,0] should succeed"),
2.0
);
let broadcast = a
.broadcast_view(&[3, 3, 3])
.expect("test: broadcast_view should succeed");
assert_eq!(broadcast.shape(), vec![3, 3, 3]);
assert_eq!(
broadcast
.get(&[0, 0, 0])
.expect("test: broadcast get [0,0,0] should succeed"),
1.0
);
assert_eq!(
broadcast
.get(&[1, 0, 0])
.expect("test: broadcast get [1,0,0] should succeed"),
1.0
);
}
#[test]
fn test_universal_functions() {
use crate::ufuncs::*;
let a = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let b = Array::<f64>::from_vec(vec![5.0, 6.0, 7.0, 8.0]);
let result = add(&a, &b).expect("test: ufunc add should succeed");
assert_eq!(result.to_vec(), vec![6.0, 8.0, 10.0, 12.0]);
let result = subtract(&a, &b).expect("test: ufunc subtract should succeed");
assert_eq!(result.to_vec(), vec![-4.0, -4.0, -4.0, -4.0]);
let result = multiply(&a, &b).expect("test: ufunc multiply should succeed");
assert_eq!(result.to_vec(), vec![5.0, 12.0, 21.0, 32.0]);
let result = divide(&a, &b).expect("test: ufunc divide should succeed");
assert_relative_eq!(result.to_vec()[0], 0.2, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[1], 1.0 / 3.0, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[2], 3.0 / 7.0, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[3], 0.5, epsilon = 1e-10);
let result = power(&a, &b).expect("test: ufunc power should succeed");
assert_relative_eq!(result.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[1], 64.0, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[2], 2187.0, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[3], 65536.0, epsilon = 1e-10);
let result = square(&a);
assert_eq!(result.to_vec(), vec![1.0, 4.0, 9.0, 16.0]);
let result = sqrt(&a);
assert_relative_eq!(result.to_vec()[0], 1.0, epsilon = 1e-10);
assert_relative_eq!(
result.to_vec()[1],
std::f64::consts::SQRT_2,
epsilon = 1e-10
);
assert_relative_eq!(result.to_vec()[2], 1.7320508075688772, epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[3], 2.0, epsilon = 1e-10);
let result = exp(&a);
assert_relative_eq!(result.to_vec()[0], 1.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[1], 2.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[2], 3.0_f64.exp(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[3], 4.0_f64.exp(), epsilon = 1e-10);
let result = log(&a);
assert_relative_eq!(result.to_vec()[0], 1.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[1], 2.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[2], 3.0_f64.ln(), epsilon = 1e-10);
assert_relative_eq!(result.to_vec()[3], 4.0_f64.ln(), epsilon = 1e-10);
let result = multiply_scalar(&a, 2.0);
assert_eq!(result.to_vec(), vec![2.0, 4.0, 6.0, 8.0]);
let row = Array::<f64>::from_vec(vec![10.0, 20.0]).reshape(&[1, 2]);
let col = Array::<f64>::from_vec(vec![1.0, 2.0, 3.0]).reshape(&[3, 1]);
let result = add(&row, &col).expect("test: ufunc add with broadcasting should succeed");
assert_eq!(result.shape(), vec![3, 2]);
assert_eq!(result.to_vec(), vec![11.0, 21.0, 12.0, 22.0, 13.0, 23.0]);
}
}