mini-ode


Namemini-ode JSON
Version 0.1.3 PyPI version JSON
download
home_pageNone
SummaryA minimalistic ODE solvers library built on top of PyTorch
upload_time2025-10-26 19:10:27
maintainerNone
docs_urlNone
authorNone
requires_python<3.15,>=3.14
licenseGPL-2.0
keywords simulation math
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # mini-ode

A minimalistic, multi-language library for solving Ordinary Differential Equations (ODEs). `mini-ode` is designed with a shared Rust core and a consistent interface for both **Rust** and **Python** users. It supports explicit, implicit, fixed step and adaptive step algorithms.

[![crates.io version](https://img.shields.io/crates/v/mini-ode)](CRATESIO_VERSION) [![crates.io downloads](https://img.shields.io/crates/d/mini-ode)](CRATESIO_DOWNLOADS) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[![PyPI version](https://img.shields.io/pypi/v/mini-ode)](PYPI_VERSION) [![PyPI monthly downloads](https://img.shields.io/pypi/dm/mini-ode)](PYPI_MONTHLY_DOWNLOADS) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
[![License: GPL-2.0](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](LICENSE)

## ✨ Features

- **Dual interface**: call the same solvers from Rust or Python
- **PyTorch-compatible**: define the derivative function using PyTorch
- **Multiple solver methods**: includes explicit, implicit, and adaptive-step solvers
- **Modular optimizers**: implicit solvers allow flexible optimizer configuration

## 🧠 Supported Solvers

| Solver Class               | Method                                 | Suitable For                                 | Implicit | Adaptive Step |
|----------------------------|----------------------------------------|----------------------------------------------|----------|----------------|
| `EulerMethodSolver`        | Euler                                  | Simple, fast, and educational use.           | ❌       | ❌             |
| `RK4MethodSolver`          | Runge-Kutta 4th Order (RK4)            | General-purpose with fixed step size.        | ❌       | ❌             |
| `ImplicitEulerMethodSolver`| Implicit Euler                         | Stiff or ill-conditioned problems.           | ✅       | ❌             |
| `GLRK4MethodSolver`        | Gauss-Legendre RK (Order 4)            | High-accuracy, stiff problems.               | ✅       | ❌             |
| `RKF45MethodSolver`        | Runge-Kutta-Fehlberg 4(5)              | Adaptive step size control.                  | ❌       | ✅             |
| `ROW1MethodSolver`         | Rosenbrock-Wanner (Order 1)            | Fast semi-implicit method for stiff systems. | semi  | ❌             |

## 📦 Building the Library

### Rust

To build the core Rust library:

```bash
cd mini-ode
cargo build --release
```

### Python

To build and install the Python package (in a virtual environment or Conda environment):

```bash
cd mini-ode-python
LIBTORCH_USE_PYTORCH=1 maturin develop
```

> This builds the Python bindings using [`maturin`](https://github.com/PyO3/maturin) and installs the package locally.

## 🐍 Python Usage Overview

To use `mini-ode` from Python:

1. Define the derivative function using `torch.Tensor` inputs.
2. **Trace** the function using `torch.jit.trace`.
3. Pass the traced function and initial conditions to a solver instance.
4. For implicit solvers, pass an optimizer at construction.

Example usage flow (not full code):

```python
import torch
import mini_ode

# 1. Define derivative function using PyTorch
def f(x: torch.Tensor, y: torch.Tensor):
    return y.flip(0) - torch.tensor([0, 1]) * (y.flip(0) ** 3)

# 2. Trace the function to TorchScript
traced_f = torch.jit.trace(f, (torch.tensor(0.), torch.tensor([[0., 0.]])))

# 3. Create a solver instance
solver = mini_ode.RK4MethodSolver(step=0.01)

# 4. Solve the ODE
xs, ys = solver.solve(traced_f, torch.tensor([0., 5.]), torch.tensor([1.0, 0.0]))
```

### 🔧 Using Optimizers (Implicit Solvers Only)

Some solvers like `GLRK4MethodSolver` or `ImplicitEulerMethodSolver` require an optimizer for nonlinear system solving:

```python
optimizer = mini_ode.optimizers.CG(
    max_steps=5,
    gtol=1e-8,
    linesearch_atol=1e-6
)

solver = mini_ode.GLRK4MethodSolver(step=0.2, optimizer=optimizer)
```

## 🦀 Rust Usage Overview

In Rust, solvers use the same logic as in Python - but you pass in a `tch::CModule` representing the TorchScripted derivative function.

**Example 1:** Load a TorchScript model from file

This approach uses a model traced in Python (e.g., with `torch.jit.trace`) and saved to disk.

```rust
use mini_ode::Solver;
use tch::{Tensor, CModule};

fn main() -> anyhow::Result<()> {
    let solver = Solver::Euler { step: 0.01 };
    let model = CModule::load("my_traced_function.pt")?;
    let x_span = Tensor::from_slice(&[0.0f64, 2.0]);
    let y0 = Tensor::from_slice(&[1.0f64, 0.0]);

    let (xs, ys) = solver.solve(model, x_span, y0)?;
    println!("{:?}", xs);
    Ok(())
}
```

**Example 2:** Trace the derivative function directly in Rust

You can also define and trace the derivative function in Rust using `CModule::create_by_tracing`.

```rust
use mini_ode::Solver;
use tch::{Tensor, CModule};

fn main() -> anyhow::Result<()> {
    // Initial value for tracing
    let y0 = Tensor::from_slice(&[1.0f64, 0.0]);

    // Define the derivative function closure
    let mut closure = |inputs: &[Tensor]| {
        let x = &inputs[0];
        let y = &inputs[1];
        let flipped = y.flip(0);
        let dy = &flipped - &(&flipped.pow_tensor_scalar(3.0) * Tensor::from_slice(&[0.0, 1.0]));
        vec![dy]
    };

    // Trace the model directly in Rust
    let model = CModule::create_by_tracing(
        "ode_fn",
        "forward",
        &[Tensor::from(0.0), y0.shallow_clone()],
        &mut closure,
    )?;

    // Use an adaptive solver, for example
    let solver = Solver::RKF45 {
        rtol: 0.00001,
        atol: 0.00001,
        min_step: 1e-9,
        safety_factor: 0.9
    };
    let x_span = Tensor::from_slice(&[0.0f64, 5.0]);

    let (xs, ys) = solver.solve(model, x_span, y0)?;
    println!("Final state: {:?}", ys);
    Ok(())
}
```

## 📁 Project Structure

```
mini-ode/           # Core Rust implementation of solvers
mini-ode-python/    # Python bindings using PyO3 + maturin
example.ipynb       # Jupyter notebook demonstrating usage
```

## 📄 License

This project is licensed under the [GPL-2.0 License](LICENSE).

## 👤 Author

**Antoni Przybylik**  
📧 [antoni@taon.io](mailto:antoni@taon.io)  
📧 [antoni.przybylik@wp.pl](mailto:antoni.przybylik@wp.pl)  
🔗 [https://github.com/antoniprzybylik](https://github.com/antoniprzybylik)


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mini-ode",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.15,>=3.14",
    "maintainer_email": null,
    "keywords": "simulation, math",
    "author": null,
    "author_email": "Antoni Przybylik <antoni.przybylik@wp.pl>",
    "download_url": null,
    "platform": null,
    "description": "# mini-ode\n\nA minimalistic, multi-language library for solving Ordinary Differential Equations (ODEs). `mini-ode` is designed with a shared Rust core and a consistent interface for both **Rust** and **Python** users. It supports explicit, implicit, fixed step and adaptive step algorithms.\n\n[![crates.io version](https://img.shields.io/crates/v/mini-ode)](CRATESIO_VERSION) [![crates.io downloads](https://img.shields.io/crates/d/mini-ode)](CRATESIO_DOWNLOADS) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n[![PyPI version](https://img.shields.io/pypi/v/mini-ode)](PYPI_VERSION) [![PyPI monthly downloads](https://img.shields.io/pypi/dm/mini-ode)](PYPI_MONTHLY_DOWNLOADS) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n[![License: GPL-2.0](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](LICENSE)\n\n## \u2728 Features\n\n- **Dual interface**: call the same solvers from Rust or Python\n- **PyTorch-compatible**: define the derivative function using PyTorch\n- **Multiple solver methods**: includes explicit, implicit, and adaptive-step solvers\n- **Modular optimizers**: implicit solvers allow flexible optimizer configuration\n\n## \ud83e\udde0 Supported Solvers\n\n| Solver Class               | Method                                 | Suitable For                                 | Implicit | Adaptive Step |\n|----------------------------|----------------------------------------|----------------------------------------------|----------|----------------|\n| `EulerMethodSolver`        | Euler                                  | Simple, fast, and educational use.           | \u274c       | \u274c             |\n| `RK4MethodSolver`          | Runge-Kutta 4th Order (RK4)            | General-purpose with fixed step size.        | \u274c       | \u274c             |\n| `ImplicitEulerMethodSolver`| Implicit Euler                         | Stiff or ill-conditioned problems.           | \u2705       | \u274c             |\n| `GLRK4MethodSolver`        | Gauss-Legendre RK (Order 4)            | High-accuracy, stiff problems.               | \u2705       | \u274c             |\n| `RKF45MethodSolver`        | Runge-Kutta-Fehlberg 4(5)              | Adaptive step size control.                  | \u274c       | \u2705             |\n| `ROW1MethodSolver`         | Rosenbrock-Wanner (Order 1)            | Fast semi-implicit method for stiff systems. | semi  | \u274c             |\n\n## \ud83d\udce6 Building the Library\n\n### Rust\n\nTo build the core Rust library:\n\n```bash\ncd mini-ode\ncargo build --release\n```\n\n### Python\n\nTo build and install the Python package (in a virtual environment or Conda environment):\n\n```bash\ncd mini-ode-python\nLIBTORCH_USE_PYTORCH=1 maturin develop\n```\n\n> This builds the Python bindings using [`maturin`](https://github.com/PyO3/maturin) and installs the package locally.\n\n## \ud83d\udc0d Python Usage Overview\n\nTo use `mini-ode` from Python:\n\n1. Define the derivative function using `torch.Tensor` inputs.\n2. **Trace** the function using `torch.jit.trace`.\n3. Pass the traced function and initial conditions to a solver instance.\n4. For implicit solvers, pass an optimizer at construction.\n\nExample usage flow (not full code):\n\n```python\nimport torch\nimport mini_ode\n\n# 1. Define derivative function using PyTorch\ndef f(x: torch.Tensor, y: torch.Tensor):\n    return y.flip(0) - torch.tensor([0, 1]) * (y.flip(0) ** 3)\n\n# 2. Trace the function to TorchScript\ntraced_f = torch.jit.trace(f, (torch.tensor(0.), torch.tensor([[0., 0.]])))\n\n# 3. Create a solver instance\nsolver = mini_ode.RK4MethodSolver(step=0.01)\n\n# 4. Solve the ODE\nxs, ys = solver.solve(traced_f, torch.tensor([0., 5.]), torch.tensor([1.0, 0.0]))\n```\n\n### \ud83d\udd27 Using Optimizers (Implicit Solvers Only)\n\nSome solvers like `GLRK4MethodSolver` or `ImplicitEulerMethodSolver` require an optimizer for nonlinear system solving:\n\n```python\noptimizer = mini_ode.optimizers.CG(\n    max_steps=5,\n    gtol=1e-8,\n    linesearch_atol=1e-6\n)\n\nsolver = mini_ode.GLRK4MethodSolver(step=0.2, optimizer=optimizer)\n```\n\n## \ud83e\udd80 Rust Usage Overview\n\nIn Rust, solvers use the same logic as in Python - but you pass in a `tch::CModule` representing the TorchScripted derivative function.\n\n**Example 1:** Load a TorchScript model from file\n\nThis approach uses a model traced in Python (e.g., with `torch.jit.trace`) and saved to disk.\n\n```rust\nuse mini_ode::Solver;\nuse tch::{Tensor, CModule};\n\nfn main() -> anyhow::Result<()> {\n    let solver = Solver::Euler { step: 0.01 };\n    let model = CModule::load(\"my_traced_function.pt\")?;\n    let x_span = Tensor::from_slice(&[0.0f64, 2.0]);\n    let y0 = Tensor::from_slice(&[1.0f64, 0.0]);\n\n    let (xs, ys) = solver.solve(model, x_span, y0)?;\n    println!(\"{:?}\", xs);\n    Ok(())\n}\n```\n\n**Example 2:** Trace the derivative function directly in Rust\n\nYou can also define and trace the derivative function in Rust using `CModule::create_by_tracing`.\n\n```rust\nuse mini_ode::Solver;\nuse tch::{Tensor, CModule};\n\nfn main() -> anyhow::Result<()> {\n    // Initial value for tracing\n    let y0 = Tensor::from_slice(&[1.0f64, 0.0]);\n\n    // Define the derivative function closure\n    let mut closure = |inputs: &[Tensor]| {\n        let x = &inputs[0];\n        let y = &inputs[1];\n        let flipped = y.flip(0);\n        let dy = &flipped - &(&flipped.pow_tensor_scalar(3.0) * Tensor::from_slice(&[0.0, 1.0]));\n        vec![dy]\n    };\n\n    // Trace the model directly in Rust\n    let model = CModule::create_by_tracing(\n        \"ode_fn\",\n        \"forward\",\n        &[Tensor::from(0.0), y0.shallow_clone()],\n        &mut closure,\n    )?;\n\n    // Use an adaptive solver, for example\n    let solver = Solver::RKF45 {\n        rtol: 0.00001,\n        atol: 0.00001,\n        min_step: 1e-9,\n        safety_factor: 0.9\n    };\n    let x_span = Tensor::from_slice(&[0.0f64, 5.0]);\n\n    let (xs, ys) = solver.solve(model, x_span, y0)?;\n    println!(\"Final state: {:?}\", ys);\n    Ok(())\n}\n```\n\n## \ud83d\udcc1 Project Structure\n\n```\nmini-ode/           # Core Rust implementation of solvers\nmini-ode-python/    # Python bindings using PyO3 + maturin\nexample.ipynb       # Jupyter notebook demonstrating usage\n```\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the [GPL-2.0 License](LICENSE).\n\n## \ud83d\udc64 Author\n\n**Antoni Przybylik**  \n\ud83d\udce7 [antoni@taon.io](mailto:antoni@taon.io)  \n\ud83d\udce7 [antoni.przybylik@wp.pl](mailto:antoni.przybylik@wp.pl)  \n\ud83d\udd17 [https://github.com/antoniprzybylik](https://github.com/antoniprzybylik)\n\n",
    "bugtrack_url": null,
    "license": "GPL-2.0",
    "summary": "A minimalistic ODE solvers library built on top of PyTorch",
    "version": "0.1.3",
    "project_urls": {
        "Homepage": "https://github.com/antoniprzybylik/mini-ode",
        "Source": "https://github.com/antoniprzybylik/mini-ode"
    },
    "split_keywords": [
        "simulation",
        " math"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2a0a4f16cc01d81d692f0131969f7a8c5852264c7191e45a6674384f5946eaa0",
                "md5": "15d52ff8e5a9212117b6686cc5084a54",
                "sha256": "bdbb69d346d3c48ec51b6be3b1d104750eca842af6fdb2d2a57a60eb46ba09da"
            },
            "downloads": -1,
            "filename": "mini_ode-0.1.3-cp313-abi3-manylinux_2_39_x86_64.whl",
            "has_sig": false,
            "md5_digest": "15d52ff8e5a9212117b6686cc5084a54",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": "<3.15,>=3.14",
            "size": 470322,
            "upload_time": "2025-10-26T19:10:27",
            "upload_time_iso_8601": "2025-10-26T19:10:27.539987Z",
            "url": "https://files.pythonhosted.org/packages/2a/0a/4f16cc01d81d692f0131969f7a8c5852264c7191e45a6674384f5946eaa0/mini_ode-0.1.3-cp313-abi3-manylinux_2_39_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-26 19:10:27",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "antoniprzybylik",
    "github_project": "mini-ode",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "mini-ode"
}
        
Elapsed time: 4.30108s