A Python library for solving higher-order ordinary differential equations (ODEs) without manual reduction.
Project description
Odecast
Write ODEs Like Math, Not Code
Stop wrestling with manual ODE reduction. Write differential equations as they appear in your textbook.
🚫 The Problem
Traditional approach: Converting high-order ODEs to first-order systems manually
# The mathematical equation: y'' + 0.3*y' + y = 0
# Must be manually converted to a system:
def system(t, z):
y, dy_dt = z
d2y_dt2 = -0.3*dy_dt - y
return [dy_dt, d2y_dt2]
# Then solve with scipy.integrate.solve_ivp
sol = solve_ivp(system, [0, 10], [1.0, 0.0])
# Which variable is which? What order? Error-prone! 😵💫
✅ The Odecast Way
Write math as math:
from odecast import var, Eq, solve
y = var("y")
eq = Eq(y.d(2) + 0.3*y.d() + y, 0) # Exactly as written in textbooks!
sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0, 10))
# Crystal clear, impossible to mess up! 🎯
🎯 Why Odecast?
"Finally, I can copy equations directly from papers into code!" - Frustrated PhD student everywhere
| Traditional Approach | Odecast Approach |
|---|---|
| 🔴 Manual reduction to first-order | ✅ Automatic order inference |
| 🔴 Error-prone variable ordering | ✅ Named variables with clear semantics |
| 🔴 Complex system setup | ✅ Write equations as they appear in papers |
| 🔴 Lost connection to original math | ✅ Maintains mathematical clarity |
| 🔴 Vector systems are nightmares | ✅ u.d(2) + u = 0 for vector ODEs |
🚀 Quick Start
pip install odecast
30-Second Example: Damped harmonic oscillator
from odecast import var, Eq, solve
# Write the equation exactly as it appears in your textbook
y = var("y")
equation = Eq(y.d(2) + 0.3*y.d() + y, 0)
# Solve it (automatically converts to first-order system)
solution = solve(
equation,
ivp={y: 1.0, y.d(): 0.0}, # y(0)=1, y'(0)=0
tspan=(0, 10)
)
# Get results
import matplotlib.pyplot as plt
plt.plot(solution.t, solution[y])
plt.show() # Beautiful decay curve! 📈
Power Features
Intuitive Syntax
# Traditional nightmare:
def system(t, z): return [z[1], -0.3*z[1] - z[0]]
# Odecast elegance:
Eq(y.d(2) + 0.3*y.d() + y, 0)
Vector Systems Made Easy
# 2D harmonic oscillator in one line:
u = var("u", shape=2)
Eq(u.d(2) + u, 0) # Automatically expands to u₀'' + u₀ = 0, u₁'' + u₁ = 0
Multiple Backends
- SciPy: Lightning-fast numerics for engineering
- SymPy: Exact symbolic solutions for analysis
- Auto: Tries numeric first, falls back to symbolic
Bulletproof Validation
# Clear error messages when you mess up:
y = var("y")
solve(Eq(y.d(2) + y, 0), ivp={y: 1.0}) # Missing y'(0)!
# ❌ ODEValidationError: Missing initial condition for y.d()
Real-World Examples
| Domain | Equation | Odecast Code |
|---|---|---|
| Physics | Mass-spring: mẍ + cẋ + kx = F(t) |
Eq(m*x.d(2) + c*x.d() + k*x, F) |
| Biology | Population: ṅ = rn(1-n/K) |
Eq(n.d() - r*n*(1-n/K), 0) |
| Engineering | RLC Circuit: Lq̈ + Rq̇ + q/C = V(t) |
Eq(L*q.d(2) + R*q.d() + q/C, V) |
| Economics | Growth: K̇ = sY - δK |
Eq(K.d() - s*Y + delta*K, 0) |
Who Uses Odecast?
- 🎓 Researchers: Copy equations directly from papers
- 👨🎓 Students: Focus on physics, not programming
- 🏭 Engineers: Rapid prototyping of dynamic systems
- 📊 Data Scientists: Time-series modeling made easy
Show Me The Code
Example 1: Pendulum with damping
θ = var("θ") # Angle
eq = Eq(θ.d(2) + 0.5*θ.d() + np.sin(θ), 0) # Non-linear!
sol = solve(eq, ivp={θ: np.pi/4, θ.d(): 0}, tspan=(0, 20))
Example 2: Lotka-Volterra (predator-prey)
x, y = var("x"), var("y") # Rabbits, foxes
eqs = [
Eq(x.d() - x*(1 - y), 0), # Rabbit growth
Eq(y.d() - y*(-1 + x), 0) # Fox dynamics
]
sol = solve(eqs, ivp={x: 1, y: 1}, tspan=(0, 15))
Example 3: Vector oscillator (physics)
u = var("u", shape=2) # 2D position
eq = Eq(u.d(2) + 0.1*u.d() + u, 0) # Damped 2D harmonic oscillator
sol = solve(eq, ivp={u: [1, 0], u.d(): [0, 1]}, tspan=(0, 10))
plt.plot(sol[u[0]], sol[u[1]]) # Phase space plot! 🌀
More Examples
from odecast import t, var, Eq, solve
# Define a variable
y = var("y")
# Create an equation: y'' + 0.3*y' + y = 0 (damped harmonic oscillator)
eq = Eq(y.d(2) + 0.3*y.d() + y, 0)
# Solve with initial conditions y(0) = 1, y'(0) = 0
sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0.0, 10.0), backend="scipy")
# Access solution data
y_values = sol[y] # Position over time
velocity = sol[y.d()] # Velocity over time
times = sol.t # Time points
# Evaluate at specific times
position_at_5s = sol.eval(y, 5.0)
---
*Built for scientists, engineers, and students who want to focus on the math, not the code.*
## Examples
The `examples/` directory contains comprehensive examples:
- `01_ivp_damped_oscillator.py` - Numeric IVP solving with visualization
- `02_symbolic_simple.py` - Symbolic solutions using SymPy backend
- `03_mixed_orders.py` - Coupled systems with mixed derivative orders
- `04_vector_harmonic_oscillator.py` - 2D harmonic oscillator using vector variables
- `05_vector_mixed_system.py` - Mixed vector/scalar systems
- `06_vector_simple.py` - Simple vector variable introduction
Run any example:
```bash
python examples/01_ivp_damped_oscillator.py
Backends
SciPy (Numeric)
# Solve numerically over a time span
sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="scipy")
SymPy (Symbolic)
# Get exact symbolic solution
sol = solve(eq, backend="sympy")
expr = sol.as_expr(y) # Returns SymPy expression
Auto Backend Selection
# Try numeric first, fall back to symbolic
sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="auto")
API Reference
Variables and Equations
var(name, order=None)- Create a scalar dependent variablevar(name, shape=n)- Create a vector variable with n componentsvar(name, shape=(m,n))- Create a matrix variable (coming soon)y.d(n)- n-th derivative of variable yu[i]- Access i-th component of vector variable uu.d(n)- n-th derivative of vector variable (returns vector derivative)Eq(lhs, rhs)- Create an equationt- Independent variable (time)
Solving
solve(equations, ivp=None, bvp=None, tspan=None, backend="auto")
Solution Objects
sol[y]- Access solution values for variable ysol[y.d()]- Access derivative valuessol[u]- Access vector solution (returns 2D array for vector variables)sol[u[i]]- Access i-th component solution (returns 1D array)sol.eval(target, time_points)- Evaluate at specific timessol.as_first_order()- Inspect first-order system representation
Contributing
This project follows a test-driven development approach. All functionality is defined by comprehensive tests.
Development Setup
git clone https://github.com/maroba/odecast.git
cd odecast
pip install -e ".[dev]"
Running Tests
pytest # Run all tests
pytest -v # Verbose output
pytest tests/test_api* # Run specific test files
Code Quality
ruff check . # Linting
black . # Formatting
Contributing Guidelines
- All new features must have comprehensive tests
- Follow the existing API patterns and naming conventions
- Add examples for significant new functionality
- Update documentation for user-facing changes
- Ensure all tests pass before submitting PRs
Status
Current implementation status:
- ✅ Core DSL (variables, equations, derivatives)
- ✅ Vector/Matrix variables with automatic equation expansion
- ✅ SciPy numeric backend (IVP)
- ✅ SymPy symbolic backend (decoupled systems)
- ✅ Automatic order inference and validation
- ✅ Comprehensive error handling
- ✅ Mixed-order coupled systems
- 🚧 BVP support (boundary value problems) - coming soon
License
MIT License - see LICENSE file for details.
📚 More Examples
Check out the examples/ directory for complete working examples:
- 🔢 Numeric solutions:
01_ivp_damped_oscillator.py - 🔣 Symbolic solutions:
02_symbolic_simple.py - 🏹 Vector systems:
04_vector_harmonic_oscillator.py - 🔗 Coupled systems:
05_vector_mixed_system.py
# Run any example
python examples/01_ivp_damped_oscillator.py
⭐ Like what you see?
Give us a star! ⭐ It helps others discover Odecast.
Share it with colleagues who are tired of manual ODE reduction.
Follow us for updates on new features and improvements.
Stop fighting with first-order systems. Start writing math like math.
⭐ Star on GitHub • 📦 Install from PyPI • 📖 Read the Docs
Made with ❤️ for scientists, engineers, and students worldwide.
Stop wrestling with manual ODE reduction. Write differential equations as they appear in your textbook.
🤝 Contributing
Want to make Odecast even better? We'd love your help!
git clone https://github.com/maroba/odecast.git
cd odecast
pip install -e ".[dev]"
pytest # Run tests
What we need:
- 📖 More examples from your field
- 🐛 Bug reports and fixes
- 🚀 Performance improvements
- 📝 Documentation improvements
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file odecast-0.1.1.tar.gz.
File metadata
- Download URL: odecast-0.1.1.tar.gz
- Upload date:
- Size: 32.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22d4451dad718a9092463f37cde463633ebf80a30ba999ccdb744f8ee077a0f1
|
|
| MD5 |
585ef01dec38a4e0e5e70119ff9a11f3
|
|
| BLAKE2b-256 |
e050e48fdab796a4d6e61afd5b7425e29c4bb752030410392903fe87ef3edd8e
|
File details
Details for the file odecast-0.1.1-py3-none-any.whl.
File metadata
- Download URL: odecast-0.1.1-py3-none-any.whl
- Upload date:
- Size: 30.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5742991b4f3888dd74d8dc4ab3ab7444cd8f674904d0a5ef43549d04bc6ecd0
|
|
| MD5 |
ea1661acf869bcd82d342286062cc432
|
|
| BLAKE2b-256 |
c2898ec4fdc6aa651c2215208aace8d305404d2ce286395f8522b77d53a2259b
|