scirs2_autograd/lib.rs
1#![allow(clippy::non_canonical_partial_ord_impl)]
2#![allow(clippy::module_inception)]
3#![allow(clippy::manual_div_ceil)]
4#![allow(clippy::let_and_return)]
5#![allow(clippy::needless_range_loop)]
6#![allow(clippy::useless_vec)]
7//! # SciRS2 Autograd - Automatic Differentiation for Rust
8#![recursion_limit = "1024"]
9//!
10//! **scirs2-autograd** provides PyTorch-style automatic differentiation with lazy tensor evaluation,
11//! enabling efficient gradient computation for scientific computing and deep learning.
12//!
13//! ## šÆ Key Features
14//!
15//! - **Reverse-mode Autodiff**: Efficient backpropagation for neural networks
16//! - **Lazy Evaluation**: Build computation graphs, evaluate only when needed
17//! - **Higher-order Gradients**: Compute derivatives of derivatives
18//! - **Neural Network Ops**: Optimized operations for deep learning
19//! - **Optimizers**: Adam, SGD, RMSprop with state management
20//! - **Model Persistence**: Save and load trained models
21//! - **Variable Management**: Namespace-based variable organization
22//!
23//! ## š¦ Installation
24//!
25//! ```toml
26//! [dependencies]
27//! scirs2-autograd = { version = "0.1.5", features = ["blas"] }
28//! ```
29//!
30//! ### BLAS Acceleration (Recommended)
31//!
32//! For fast matrix operations, enable BLAS (uses OxiBLAS - pure Rust):
33//!
34//! ```toml
35//! [dependencies]
36//! scirs2-autograd = { version = "0.1.5", features = ["blas"] }
37//! ```
38//!
39//! ## š Quick Start
40//!
41//! ### Basic Differentiation
42//!
43//! Compute gradients of a simple function:
44//!
45//! ```rust
46//! use scirs2_autograd as ag;
47//! use ag::tensor_ops as T;
48//!
49//! ag::run(|ctx: &mut ag::Context<f64>| {
50//! // Define variables
51//! let x = ctx.placeholder("x", &[]);
52//! let y = ctx.placeholder("y", &[]);
53//!
54//! // Build computation graph: z = 2x² + 3y + 1
55//! let z = 2.0 * x * x + 3.0 * y + 1.0;
56//!
57//! // Compute dz/dy
58//! let dz_dy = &T::grad(&[z], &[y])[0];
59//! println!("dz/dy = {:?}", dz_dy.eval(ctx)); // => 3.0
60//!
61//! // Compute dz/dx (feed x=2)
62//! let dz_dx = &T::grad(&[z], &[x])[0];
63//! let x_val = scirs2_core::ndarray::arr0(2.0);
64//! let result = ctx.evaluator()
65//! .push(dz_dx)
66//! .feed(x, x_val.view().into_dyn())
67//! .run()[0].clone();
68//! println!("dz/dx at x=2: {:?}", result); // => 8.0
69//!
70//! // Higher-order: d²z/dx²
71//! let d2z_dx2 = &T::grad(&[dz_dx], &[x])[0];
72//! println!("d²z/dx² = {:?}", d2z_dx2.eval(ctx)); // => 4.0
73//! });
74//! ```
75//!
76//! ### Neural Network Training
77//!
78//! Train a multi-layer perceptron for MNIST:
79//!
80//! ```rust
81//! use scirs2_autograd as ag;
82//! use ag::optimizers::adam::Adam;
83//! use ag::tensor_ops::*;
84//! use ag::prelude::*;
85//!
86//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
87//! // Create variable environment
88//! let mut env = ag::VariableEnvironment::new();
89//! let mut rng = ag::ndarray_ext::ArrayRng::<f32>::default();
90//!
91//! // Initialize network weights
92//! env.name("w1").set(rng.glorot_uniform(&[784, 256]));
93//! env.name("b1").set(ag::ndarray_ext::zeros(&[1, 256]));
94//! env.name("w2").set(rng.glorot_uniform(&[256, 10]));
95//! env.name("b2").set(ag::ndarray_ext::zeros(&[1, 10]));
96//!
97//! // Create Adam optimizer
98//! let var_ids = env.default_namespace().current_var_ids();
99//! let adam = Adam::default("adam", var_ids, &mut env);
100//!
101//! // Training loop
102//! for epoch in 0..10 {
103//! env.run(|ctx| {
104//! // Define computation graph
105//! let x = ctx.placeholder("x", &[-1, 784]);
106//! let y = ctx.placeholder("y", &[-1]);
107//!
108//! let w1 = ctx.variable("w1");
109//! let b1 = ctx.variable("b1");
110//! let w2 = ctx.variable("w2");
111//! let b2 = ctx.variable("b2");
112//!
113//! // Forward pass: x -> hidden -> output
114//! let hidden = relu(matmul(x, w1) + b1);
115//! let logits = matmul(hidden, w2) + b2;
116//!
117//! // Loss: cross-entropy
118//! let loss = reduce_mean(
119//! sparse_softmax_cross_entropy(logits, &y),
120//! &[0],
121//! false
122//! );
123//!
124//! // Backpropagation
125//! let params = &[w1, b1, w2, b2];
126//! let grads = &grad(&[loss], params);
127//!
128//! // Update weights (requires actual data feeding)
129//! // let mut feeder = ag::Feeder::new();
130//! // feeder.push(x, x_batch).push(y, y_batch);
131//! // adam.update(params, grads, ctx, feeder);
132//! });
133//! }
134//! # Ok(())
135//! # }
136//! ```
137//!
138//! ### Custom Operations
139//!
140//! Define custom differentiable operations:
141//!
142//! ```rust
143//! use scirs2_autograd as ag;
144//! use ag::tensor_ops::*;
145//!
146//! ag::run::<f64, _, _>(|ctx| {
147//! let x = ones(&[3, 4], ctx);
148//!
149//! // Apply custom transformations using tensor.map()
150//! let y = x.map(|arr| arr.mapv(|v: f64| v * 2.0 + 1.0));
151//!
152//! // Hooks for debugging
153//! let z = x.showshape(); // Print shape
154//! let w = x.raw_hook(|arr| println!("Tensor value: {}", arr));
155//! });
156//! ```
157//!
158//! ## š§ Core Concepts
159//!
160//! ### Tensors
161//!
162//! Lazy-evaluated multi-dimensional arrays with automatic gradient tracking:
163//!
164//! ```rust,no_run
165//! use scirs2_autograd as ag;
166//! use ag::tensor_ops::*;
167//! use ag::prelude::*;
168//!
169//! ag::run::<f64, _, _>(|ctx| {
170//! // Create tensors
171//! let a = zeros(&[2, 3], ctx); // All zeros
172//! let b = ones(&[2, 3], ctx); // All ones
173//! let c = ctx.placeholder("c", &[2, 3]); // Placeholder (fill later)
174//! let d = ctx.variable("d"); // Trainable variable
175//! });
176//! ```
177//!
178//! ### Computation Graphs
179//!
180//! Build graphs of operations, evaluate lazily:
181//!
182//! ```rust
183//! use scirs2_autograd as ag;
184//! use ag::tensor_ops as T;
185//!
186//! ag::run::<f64, _, _>(|ctx| {
187//! let x = ctx.placeholder("x", &[2, 2]);
188//! let y = ctx.placeholder("y", &[2, 2]);
189//!
190//! // Build graph (no computation yet)
191//! let z = T::matmul(x, y);
192//! let w = T::sigmoid(z);
193//!
194//! // Evaluate when needed
195//! // let result = w.eval(ctx);
196//! });
197//! ```
198//!
199//! ### Gradient Computation
200//!
201//! Reverse-mode automatic differentiation:
202//!
203//! ```rust
204//! use scirs2_autograd as ag;
205//! use ag::tensor_ops as T;
206//!
207//! ag::run(|ctx| {
208//! let x = ctx.placeholder("x", &[]);
209//! let y = x * x * x; // y = x³
210//!
211//! // Compute dy/dx = 3x²
212//! let dy_dx = &T::grad(&[y], &[x])[0];
213//!
214//! // Evaluate at x=2: 3(2²) = 12
215//! let x_val = scirs2_core::ndarray::arr0(2.0);
216//! let grad_val = ctx.evaluator()
217//! .push(dy_dx)
218//! .feed(x, x_val.view().into_dyn())
219//! .run()[0].clone();
220//! });
221//! ```
222//!
223//! ## šØ Available Operations
224//!
225//! ### Basic Math
226//!
227//! - Arithmetic: `+`, `-`, `*`, `/`, `pow`
228//! - Comparison: `equal`, `not_equal`, `greater`, `less`
229//! - Reduction: `sum`, `mean`, `max`, `min`
230//!
231//! ### Neural Network Ops
232//!
233//! - Activations: `relu`, `sigmoid`, `tanh`, `softmax`, `gelu`
234//! - Pooling: `max_pool2d`, `avg_pool2d`
235//! - Convolution: `conv2d`, `conv2d_transpose`
236//! - Normalization: `batch_norm`, `layer_norm`
237//! - Dropout: `dropout`
238//!
239//! ### Matrix Operations
240//!
241//! - `matmul` - Matrix multiplication
242//! - `transpose` - Matrix transpose
243//! - `reshape` - Change tensor shape
244//! - `concat` - Concatenate tensors
245//! - `split` - Split tensor
246//!
247//! ### Loss Functions
248//!
249//! - `sparse_softmax_cross_entropy` - Classification loss
250//! - `sigmoid_cross_entropy` - Binary classification
251//! - `softmax_cross_entropy` - Multi-class loss
252//!
253//! ## š§ Optimizers
254//!
255//! Built-in optimization algorithms:
256//!
257//! - **Adam**: Adaptive moment estimation (recommended)
258//! - **SGD**: Stochastic gradient descent with momentum
259//! - **RMSprop**: Root mean square propagation
260//! - **Adagrad**: Adaptive learning rates
261//!
262//! ## š¾ Model Persistence
263//!
264//! Save and load trained models:
265//!
266//! ```rust,no_run
267//! use scirs2_autograd as ag;
268//!
269//! let mut env = ag::VariableEnvironment::<f64>::new();
270//!
271//! // After training...
272//! env.save("model.safetensors")?;
273//!
274//! // Later, load the model
275//! let env = ag::VariableEnvironment::<f64>::load("model.safetensors")?;
276//! # Ok::<(), Box<dyn std::error::Error>>(())
277//! ```
278//!
279//! ## š Performance
280//!
281//! scirs2-autograd is designed for efficiency:
282//!
283//! - **Lazy Evaluation**: Build graphs without computation overhead
284//! - **Minimal Allocations**: Reuse memory where possible
285//! - **BLAS Integration**: Fast matrix operations via OxiBLAS (pure Rust)
286//! - **Zero-copy**: Efficient data handling with ndarray views
287//!
288//! Typical training speed: **0.11 sec/epoch** for MNIST MLP (2.7GHz Intel Core i5)
289//!
290//! ## š Integration
291//!
292//! - **scirs2-neural**: High-level neural network layers
293//! - **scirs2-linalg**: Matrix operations
294//! - **scirs2-optimize**: Optimization algorithms
295//! - **ndarray**: Core array library (re-exported)
296//!
297//! ## š Comparison with PyTorch
298//!
299//! | Feature | PyTorch | scirs2-autograd |
300//! |---------|---------|-----------------|
301//! | Autodiff | ā
| ā
|
302//! | Dynamic Graphs | ā
| ā
|
303//! | GPU Support | ā
| ā ļø (limited) |
304//! | Type Safety | ā | ā
|
305//! | Memory Safety | ā ļø | ā
|
306//! | Pure Rust | ā | ā
|
307//!
308//! ## š Version
309//!
310//! Current version: **0.1.5** (Released January 15, 2026)
311
312#[allow(unused_imports)]
313// Re-export from scirs2-core for POLICY compliance
314pub use scirs2_core::ndarray;
315pub use scirs2_core::random as rand;
316
317// BLAS dependencies now handled through scirs2-core
318
319extern crate approx;
320extern crate libc;
321extern crate matrixmultiply;
322extern crate num;
323// extern crate rayon; // Now use scirs2-core parallel abstractions
324extern crate rustc_hash;
325extern crate serde;
326extern crate serde_json;
327pub(crate) extern crate smallvec;
328extern crate special;
329extern crate uuid;
330
331pub mod error;
332pub mod error_helpers;
333pub mod evaluation;
334mod gradient;
335pub mod gradient_clipping;
336pub mod graph;
337pub mod high_performance;
338pub mod hooks;
339pub mod integration;
340pub mod ndarray_ext;
341pub mod op;
342pub mod optimization;
343pub mod optimizers;
344pub mod parallel;
345pub mod prelude;
346pub mod schedulers;
347pub mod tensor;
348pub mod tensor_ops;
349pub mod test_helper;
350pub mod testing;
351pub mod tracing;
352pub mod validation;
353pub mod variable;
354pub mod visualization;
355
356use rustc_hash::{FxHashMap, FxHashSet};
357use std::any::TypeId;
358use std::fmt;
359
360/// A primitive type in this crate, which is actually a decorated `scirs2_core::numeric::Float`.
361pub trait Float:
362 scirs2_core::numeric::Float
363 + scirs2_core::numeric::NumAssignOps
364 + Copy
365 + Send
366 + Sync
367 + fmt::Display
368 + fmt::Debug
369 + Sized
370 + serde::Serialize
371 + serde::de::DeserializeOwned
372 + 'static
373{
374}
375
376#[doc(hidden)]
377/// Internal trait.
378pub trait Int:
379 num::Integer
380 + scirs2_core::numeric::NumAssignOps
381 + scirs2_core::numeric::ToPrimitive
382 + Copy
383 + Send
384 + fmt::Display
385 + Sized
386 + serde::Serialize
387 + serde::de::DeserializeOwned
388 + 'static
389{
390}
391
392impl<T> Float for T where
393 T: num::Float
394 + scirs2_core::numeric::NumAssignOps
395 + Copy
396 + Send
397 + Sync
398 + fmt::Display
399 + fmt::Debug
400 + Sized
401 + serde::Serialize
402 + serde::de::DeserializeOwned
403 + 'static
404{
405}
406
407impl<T> Int for T where
408 T: num::Integer
409 + scirs2_core::numeric::NumAssignOps
410 + scirs2_core::numeric::ToPrimitive
411 + Copy
412 + Send
413 + Sync
414 + fmt::Display
415 + Sized
416 + serde::Serialize
417 + serde::de::DeserializeOwned
418 + 'static
419{
420}
421
422#[inline(always)]
423/// Return `true` if `A` and `B` are the same type
424pub(crate) fn same_type<A: 'static, B: 'static>() -> bool {
425 TypeId::of::<A>() == TypeId::of::<B>()
426}
427
428pub use crate::ndarray_ext::array_gen;
429
430pub use crate::ndarray_ext::{NdArray, NdArrayView, NdArrayViewMut};
431
432pub use crate::evaluation::{Evaluator, Feeder};
433
434pub use crate::tensor::Tensor;
435
436pub(crate) use graph::Graph;
437
438pub use crate::error::{AutogradError, EvalError, OpError, Result};
439pub use crate::graph::{run, Context};
440pub use crate::high_performance::{
441 memory_efficient_grad_accumulation, parallel_gradient_computation, simd_backward_pass,
442 ultra_backward_pass,
443};
444pub use crate::variable::{
445 AutogradTensor, SafeVariable, SafeVariableEnvironment, VariableEnvironment,
446};
447
448// Re-export functional optimizers and training utilities (Issue #94)
449pub use crate::optimizers::{FunctionalAdam, FunctionalOptimizer, FunctionalSGD};