multicalc 0.6.0

Rust scientific computing for single and multi-variable calculus
Documentation
# multicalc

[![On crates.io](https://img.shields.io/crates/v/multicalc.svg)](https://crates.io/crates/multicalc)
![Downloads](https://img.shields.io/crates/d/multicalc?style=flat-square)
[![CI](https://github.com/kmolan/multicalc-rust/actions/workflows/ci.yml/badge.svg)](https://github.com/kmolan/multicalc-rust/actions/workflows/ci.yml)
[![Docs](https://docs.rs/multicalc/badge.svg)](https://docs.rs/multicalc)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)

`multicalc` is a Rust library for single- and multi-variable calculus: derivatives, integrals,
Jacobians and Hessians, vector-field operators, and Taylor approximation in a `no-std` environment.

## Why use it

- Pure, safe Rust.
- `no_std`, with no heap allocation and no panics — it runs on bare-metal and embedded targets.
- Transcendental functions come from [`libm`]https://crates.io/crates/libm, so the math works
  without `std`.
- Every fallible call returns a typed [`CalcError`]./src/utils/error_codes.rs; convenience
  wrappers fill in sensible defaults.
- A runnable example for every module, and a test suite covering each error path.

## What it does

- **Differentiation** of any order (finite differences), total and partial.
- **Integration** of any order:
  - Iterative rules — Boole, Simpson, Trapezoidal — over finite, semi-infinite, and infinite limits.
  - Gaussian quadrature — Gauss-Legendre, Gauss-Hermite, Gauss-Laguerre.
- **Jacobian** and **Hessian** matrices.
- **Vector calculus** — line and flux integrals, curl, and divergence.
- **Approximation** — linear and quadratic (Taylor) models, with goodness-of-fit metrics.

## Install

```sh
cargo add multicalc
```

Enable the `alloc` feature if you want the heap-based methods (see [Heap allocation](#heap-allocation)).

### A note on `no_std`

Methods like `f64::sin` are only available with `std`. In a `no_std` crate, call the `libm` versions
instead — for example `libm::sin(x)` in place of `x.sin()`. `multicalc` re-exports `libm`, so you can
reach it as `multicalc::libm`. The examples below use `x.sin()` because they assume `std`.

## At a glance

### Derivatives

```rust
use multicalc::numerical_derivative::derivator::DerivatorSingleVariable;
use multicalc::numerical_derivative::finite_difference::FiniteDifferenceSingle;

let f = |x: f64| x * x * x;                  // f(x) = x^3
let d = FiniteDifferenceSingle::default();   // central difference, default step size

let first = d.get(1, &f, 2.0).unwrap();      // 12.0
let third = d.get(3, &f, 2.0).unwrap();      //  6.0
// get_single / get_double are wrappers for orders 1 and 2
```

For several variables, the derivative order is just the number of indices you pass:

```rust
use multicalc::numerical_derivative::derivator::DerivatorMultiVariable;
use multicalc::numerical_derivative::finite_difference::FiniteDifferenceMulti;

// g(x, y, z) = y*sin(x) + x*cos(y) + x*y*e^z
let g = |v: &[f64; 3]| v[1] * v[0].sin() + v[0] * v[1].cos() + v[0] * v[1] * v[2].exp();
let d = FiniteDifferenceMulti::default();
let point = [1.0, 2.0, 3.0];

let dx    = d.get_single_partial(&g, 0, &point).unwrap();  // dg/dx
let mixed = d.get(&g, &[0, 1], &point).unwrap();           // d(dg/dx)/dy
```

### Integration

```rust
use multicalc::numerical_integration::integrator::IntegratorSingleVariable;
use multicalc::numerical_integration::iterative_integration::IterativeSingle;

let f = |x: f64| 2.0 * x;
let integrator = IterativeSingle::default();   // Boole's rule, 120 intervals

let area = integrator.get_single(&f, &[0.0, 2.0]).unwrap();   // 4.0

// infinite and semi-infinite limits are supported for decaying integrands
let bell = integrator
    .get_single(&|x| (-x * x).exp(), &[f64::NEG_INFINITY, f64::INFINITY])
    .unwrap();                                                // sqrt(pi)
```

Choose the rule and interval count with `from_parameters`:

```rust
use multicalc::numerical_integration::mode::IterativeMethod;
let integrator = IterativeSingle::from_parameters(120, IterativeMethod::Simpsons);
```

### Gaussian quadrature

Each Gaussian rule integrates over a fixed domain. Pass the **bare** integrand `f(x)` — the weights
already carry the weighting factor.

```rust
use multicalc::numerical_integration::integrator::IntegratorSingleVariable;
use multicalc::numerical_integration::gaussian_integration::GaussianSingle;
use multicalc::numerical_integration::mode::GaussianQuadratureMethod;

// Gauss-Hermite integrates f(x) * e^(-x^2) over the whole real line.
let hermite = GaussianSingle::from_parameters(5, GaussianQuadratureMethod::GaussHermite);
let val = hermite
    .get_single(&|x| x * x, &[f64::NEG_INFINITY, f64::INFINITY])
    .unwrap();                                                // sqrt(pi)/2
```

| Rule           | Computes                                            |
| -------------- | --------------------------------------------------- |
| Gauss-Legendre | $\int_a^b f(x)\, \mathrm{d}x$                        |
| Gauss-Laguerre | $\int_0^\infty f(x)\, e^{-x}\, \mathrm{d}x$          |
| Gauss-Hermite  | $\int_{-\infty}^\infty f(x)\, e^{-x^2}\, \mathrm{d}x$ |

### Jacobian and Hessian

```rust
use multicalc::numerical_derivative::finite_difference::FiniteDifferenceMulti;
use multicalc::numerical_derivative::jacobian::Jacobian;
use multicalc::numerical_derivative::hessian::Hessian;

let f1 = |v: &[f64; 3]| v[0] * v[1] * v[2];
let f2 = |v: &[f64; 3]| v[0] * v[0] + v[1] * v[1];
let functions: [&dyn Fn(&[f64; 3]) -> f64; 2] = [&f1, &f2];

let jacobian = Jacobian::<FiniteDifferenceMulti>::default();
let j = jacobian.get(&functions, &[1.0, 2.0, 3.0]).unwrap();   // [[6, 3, 2], [2, 4, 0]]

let g = |v: &[f64; 2]| v[1] * v[0].sin() + 2.0 * v[0] * v[1].exp();
let hessian = Hessian::<FiniteDifferenceMulti>::default();
let h = hessian.get(&g, &[1.0, 2.0]).unwrap();
```

### Vector calculus

```rust
use multicalc::numerical_derivative::finite_difference::FiniteDifferenceMulti;
use multicalc::vector_field::{curl, divergence, line_integral, flux_integral};

// field (2xy, 3cos y)
let field: [&dyn Fn(&[f64; 2]) -> f64; 2] =
    [&(|v: &[f64; 2]| 2.0 * v[0] * v[1]), &(|v: &[f64; 2]| 3.0 * v[1].cos())];
let derivator = FiniteDifferenceMulti::default();
let c = curl::get_2d(derivator, &field, &[1.0, 3.14]).unwrap();
let d = divergence::get_2d(derivator, &field, &[1.0, 3.14]).unwrap();

// field (y, -x) along the unit circle (cos t, sin t)
let g: [&dyn Fn(&[f64; 2]) -> f64; 2] = [&(|v: &[f64; 2]| v[1]), &(|v: &[f64; 2]| -v[0])];
let curve: [&dyn Fn(f64) -> f64; 2] = [&(|t: f64| t.cos()), &(|t: f64| t.sin())];
let limit = [0.0, 2.0 * std::f64::consts::PI];
let line = line_integral::get_2d(&g, &curve, &limit).unwrap();   // -2*pi
let flux = flux_integral::get_2d(&g, &curve, &limit).unwrap();   //  0
```

### Approximation

```rust
use multicalc::approximation::linear_approximation::LinearApproximator;
use multicalc::numerical_derivative::finite_difference::FiniteDifferenceMulti;

let f = |v: &[f64; 3]| v[0] + v[1] * v[1] + v[2] * v[2] * v[2];
let model = LinearApproximator::<FiniteDifferenceMulti>::default()
    .get(&f, &[1.0, 2.0, 3.0])
    .unwrap();

let y = model.predict(&[1.1, 2.1, 3.1]);
// model.get_prediction_metrics(&samples, &f) returns RMSE, R^2, and more
```

`QuadraticApproximator` works the same way and captures curvature as well.

## Error handling

Where a sensible default exists, a "safe" wrapper (such as `get_single` or `get_double`) returns the
answer directly. Otherwise the call returns `Result<f64, CalcError>`, so you decide how to handle bad
input. All variants are listed in [error_codes.rs](./src/utils/error_codes.rs).

## Heap allocation

By default everything uses fixed-size stack arrays. Enable the `alloc` feature for `Vec`-based methods
that handle inputs too large for the stack. This currently covers the Jacobian's `get_on_heap`, which
returns a `Vec<Vec<f64>>`.

## Examples

Runnable, self-contained programs for each module live in [`examples/`](./examples) — see
[examples/README.md](./examples/README.md). Run one with:

```sh
cargo run --example <name>
```

## Benchmarks

See [BENCHMARKS.md](./BENCHMARKS.md) for accuracy figures and measured latency.

## Contributing

See [CONTRIBUTIONS.md](./CONTRIBUTIONS.md).

## License

multicalc is licensed under the MIT license.

## Contact

anmolkathail@gmail.com