micro_grad 0.1.0

A minimal autograd + MLP engine in Rust
Documentation
# 🦀 micro_grad — A tiny autograd + MLP engine in pure Rust

[![Crates.io](https://img.shields.io/crates/v/micro_grad.svg)](https://crates.io/crates/micro_grad)
[![Docs.rs](https://docs.rs/micro_grad/badge.svg)](https://docs.rs/micro_grad)
[![License](https://img.shields.io/badge/license-MIT%20or%20Apache--2.0-blue.svg)](./LICENSE)

A **minimal scalar autograd engine and small MLP framework** inspired by [micrograd (by Karpathy)](https://github.com/karpathy/micrograd), implemented **entirely in Rust**.
It supports basic operations (`+`, `-`, `*`, `/`, `ReLU`), backpropagation, and multi-layer perceptron training.

---

## ✨ Features

- **Automatic differentiation** on scalar computation graphs
-**Topological backward pass** (DFS-based)
-**ReLU / LeakyReLU activation**
-**Multi-layer perceptron (MLP)** abstraction
-**SGD training loop demo**
- ✅ Fully safe, `Rc<RefCell<>>` based — no `unsafe` code

---

## 📦 Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
micro_grad = "0.1"
````

Then in your Rust code:

```rust
use micro_grad::value::Var;
use micro_grad::nn::{MLP, Module};
```

---

## 🚀 Quick Start

Train an XOR neural network from scratch:

```rust
use micro_grad::nn::{MLP, Module};
use micro_grad::value::Var;

fn mse_loss(pred: &Var, target: &Var) -> Var {
    let diff = pred.sub(target);
    diff.mul(&diff)
}

fn to_vars(xs: &[f64]) -> Vec<Var> {
    xs.iter().map(|&v| Var::new(v)).collect()
}

fn main() {
    // XOR dataset
    let dataset = vec![
        (vec![0.0, 0.0], 0.0),
        (vec![0.0, 1.0], 1.0),
        (vec![1.0, 0.0], 1.0),
        (vec![1.0, 1.0], 0.0),
    ];

    // MLP: 2 -> 4 -> 1
    let mlp = MLP::new(2, &[4, 1]);
    let lr = 0.1;

    for epoch in 1..=2000 {
        let mut total_loss = Var::new(0.0);
        for (x, y) in &dataset {
            let y_true = Var::new(*y);
            let y_pred = mlp.forward_scalar(&to_vars(x));
            total_loss = total_loss.add(&mse_loss(&y_pred, &y_true));
        }

        Var::backward(&total_loss);
        for p in mlp.parameters() {
            p.set_data(p.data_of() - lr * p.grad_of());
        }

        if epoch % 100 == 0 {
            println!("epoch {epoch}, loss = {:.6}", total_loss.data_of());
        }
    }

    println!("\n== After training ==");
    for (x, y) in &dataset {
        let y_pred = mlp.forward_scalar(&to_vars(x)).data_of();
        println!("x={:?} -> pred={:.3} (target={})", x, y_pred, y);
    }
}
```

✅ Expected output (after ~1000 epochs):

```
epoch 2000, loss = 0.000000

== After training ==
x=[0.0, 0.0] -> pred≈0.00 (target=0)
x=[0.0, 1.0] -> pred≈1.00 (target=1)
x=[1.0, 0.0] -> pred≈1.00 (target=1)
x=[1.0, 1.0] -> pred≈0.00 (target=0)
```

---

## 🧠 How it works

* Each `Var` stores:

  * `data`: the scalar value
  * `grad`: the accumulated gradient
  * `Op`: reference to how it was created (`Add`, `Mul`, etc.)
* `Var::backward()` performs a **reverse topological traversal**, applying the chain rule.

A minimal graph example:

```rust
let a = Var::new(2.0);
let b = Var::new(3.0);
let c = a.mul(&b);  // c = a * b
let d = c.add(&a);  // d = a*b + a
Var::backward(&d);
println!("∂d/∂a = {}, ∂d/∂b = {}", a.grad_of(), b.grad_of());
// ∂d/∂a = b + 1 = 4, ∂d/∂b = a = 2
```

---

## 🧩 Roadmap

* [x] Scalar autograd
* [x] ReLU / LeakyReLU
* [x] MLP training example

---

## 📄 License

Licensed under either of

* MIT license ([LICENSE-MIT]LICENSE-MIT or [http://opensource.org/licenses/MIT]http://opensource.org/licenses/MIT)
* Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE or [http://www.apache.org/licenses/LICENSE-2.0]http://www.apache.org/licenses/LICENSE-2.0)

---

## 🧑‍💻 Author

Developed by **BriceLucifer**
Inspired by Andrej Karpathy’s [micrograd](https://github.com/karpathy/micrograd).

---