odecast 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+ *.egg
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ *.pyo
10
+ *.pyd
11
+ *.db
12
+ *.sqlite3
13
+
14
+ # Hatchling/Packaging
15
+ *.wheel
16
+ *.egg-info/
17
+ *.eggs/
18
+ *.manifest
19
+ *.spec
20
+
21
+ # Jupyter Notebooks
22
+ .ipynb_checkpoints/
23
+
24
+ # VS Code
25
+ .vscode/
26
+ .history/
27
+
28
+ # Test/coverage
29
+ .coverage
30
+ htmlcov/
31
+ .tox/
32
+ .pytest_cache/
33
+ .cache/
34
+ .nox/
35
+ .mypy_cache/
36
+ .dmypy.json
37
+ .pyre/
38
+ *.cover
39
+ *.log
40
+
41
+ # Environment
42
+ .env
43
+ .venv
44
+ env/
45
+ venv/
46
+ ENV/
47
+ env.bak/
48
+ venv.bak/
49
+
50
+ # OS
51
+ .DS_Store
52
+ Thumbs.db
53
+
54
+ # Misc
55
+ *.bak
56
+ *.swp
57
+ *.tmp
58
+ *.orig
59
+ TODOs.md
odecast-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,288 @@
1
+ Metadata-Version: 2.4
2
+ Name: odecast
3
+ Version: 0.1.0
4
+ Summary: A Python library for solving higher-order ordinary differential equations (ODEs) without manual reduction.
5
+ Project-URL: Homepage, https://github.com/maroba/odecast
6
+ Project-URL: Repository, https://github.com/maroba/odecast
7
+ Author-email: Matthias Baer <matthias.r.baer@googlemail.com>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.10
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest; extra == 'dev'
19
+ Requires-Dist: pytest-cov; extra == 'dev'
20
+ Provides-Extra: math
21
+ Requires-Dist: matplotlib; extra == 'math'
22
+ Requires-Dist: numpy; extra == 'math'
23
+ Requires-Dist: scipy; extra == 'math'
24
+ Requires-Dist: sympy; extra == 'math'
25
+ Description-Content-Type: text/markdown
26
+
27
+
28
+ # <img src="https://github.com/maroba/odecast/raw/main/docs/odecast-logo.png" alt="Odecast Logo" width="120" align="left" />
29
+
30
+ # Odecast
31
+
32
+ [![PyPI version](https://img.shields.io/pypi/v/odecast.svg)](https://pypi.org/project/odecast/)
33
+ [![License](https://img.shields.io/github/license/maroba/odecast)](https://github.com/maroba/odecast/blob/main/LICENSE)
34
+ [![Tests](https://github.com/maroba/odecast/actions/workflows/test.yml/badge.svg)](https://github.com/maroba/odecast/actions)
35
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
36
+
37
+ A Python library for solving higher-order ordinary differential equations (ODEs) without manual reduction. Write equations in natural mathematical form (e.g. `y.d(2) + 0.3*y.d() + y = 0`) and let odecast handle order inference, validation, conversion to first-order systems, and solving via SymPy (symbolic) or SciPy (numeric).
38
+
39
+ ## Features
40
+
41
+ - **Intuitive syntax**: Write ODEs as they appear in textbooks using `y.d(2)` for derivatives
42
+ - **Vector/Matrix variables**: Support for systems with `var("u", shape=2)` and component access `u[0]`, `u[1]`
43
+ - **Multiple backends**: Symbolic solutions via SymPy, numeric solutions via SciPy
44
+ - **Automatic order inference**: No need to manually convert to first-order systems
45
+ - **Automatic equation expansion**: Vector equations automatically expand to component equations
46
+ - **Comprehensive validation**: Clear error messages for missing or inconsistent conditions
47
+ - **Flexible interface**: Support for IVP (initial value problems) and BVP (boundary value problems)
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install -e ".[math,dev]"
53
+ ```
54
+
55
+ ## Quick Start
56
+
57
+ ```python
58
+ from odecast import t, var, Eq, solve
59
+
60
+ # Define a variable
61
+ y = var("y")
62
+
63
+ # Create an equation: y'' + 0.3*y' + y = 0 (damped harmonic oscillator)
64
+ eq = Eq(y.d(2) + 0.3*y.d() + y, 0)
65
+
66
+ # Solve with initial conditions y(0) = 1, y'(0) = 0
67
+ sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0.0, 10.0), backend="scipy")
68
+
69
+ # Access solution data
70
+ y_values = sol[y] # Position over time
71
+ velocity = sol[y.d()] # Velocity over time
72
+ times = sol.t # Time points
73
+
74
+ # Evaluate at specific times
75
+ position_at_5s = sol.eval(y, 5.0)
76
+
77
+ # Vector variables for systems
78
+ u = var("u", shape=2) # 2D vector variable
79
+ eq_vector = Eq(u.d(2) + u, 0) # Vector harmonic oscillator
80
+ sol_vector = solve(eq_vector,
81
+ ivp={u: [1.0, 0.0], u.d(): [0.0, 1.0]},
82
+ tspan=(0, 5), backend="scipy")
83
+ positions = sol_vector[u] # 2×N array of [x, y] positions
84
+ ```
85
+
86
+ ## Vector/Matrix Variables
87
+
88
+ Odecast supports vector and matrix variables for systems of equations, making it easy to work with multi-dimensional problems.
89
+
90
+ ### Creating Vector Variables
91
+
92
+ ```python
93
+ from odecast import t, var, Eq, solve
94
+
95
+ # Create a 2D vector variable
96
+ u = var("u", shape=2) # Creates u with components u[0], u[1]
97
+
98
+ # Create a 3D vector variable
99
+ v = var("v", shape=3) # Creates v with components v[0], v[1], v[2]
100
+
101
+ # Matrix variables (coming soon)
102
+ # A = var("A", shape=(2, 2)) # 2x2 matrix
103
+ ```
104
+
105
+ ### Component Access
106
+
107
+ ```python
108
+ u = var("u", shape=2)
109
+
110
+ # Access individual components
111
+ u0 = u[0] # First component
112
+ u1 = u[1] # Second component
113
+
114
+ # Components behave like regular variables
115
+ eq1 = Eq(u[0].d(2) + u[0], 0) # u₀'' + u₀ = 0
116
+ eq2 = Eq(u[1].d() + u[0], 0) # u₁' + u₀ = 0
117
+ ```
118
+
119
+ ### Vector Operations
120
+
121
+ ```python
122
+ u = var("u", shape=2)
123
+
124
+ # Vector derivatives
125
+ u_dot = u.d() # First derivative: [u[0]', u[1]']
126
+ u_ddot = u.d(2) # Second derivative: [u[0]'', u[1]'']
127
+
128
+ # Vector equations automatically expand to component equations
129
+ eq = Eq(u.d(2) + u, 0) # Becomes: u[0]'' + u[0] = 0, u[1]'' + u[1] = 0
130
+
131
+ # Vector arithmetic
132
+ position = var("r", shape=2)
133
+ velocity = var("v", shape=2)
134
+ eq1 = Eq(position.d() - velocity, 0) # r' = v
135
+ eq2 = Eq(velocity.d() + 0.1*velocity, 0) # v' + 0.1v = 0 (damping)
136
+ ```
137
+
138
+ ### Vector Initial Conditions
139
+
140
+ ```python
141
+ u = var("u", shape=2)
142
+ eq = Eq(u.d(2) + u, 0) # 2D harmonic oscillator
143
+
144
+ # Vector-style initial conditions
145
+ ivp = {
146
+ u: [1.0, 0.5], # u(0) = [1.0, 0.5]
147
+ u.d(): [0.0, -0.2] # u'(0) = [0.0, -0.2]
148
+ }
149
+
150
+ sol = solve(eq, ivp=ivp, tspan=(0, 10), backend="scipy")
151
+
152
+ # Access vector solution (returns 2×N array)
153
+ u_trajectory = sol[u] # Shape: (2, num_timepoints)
154
+
155
+ # Access individual components (returns 1D arrays)
156
+ u0_trajectory = sol[u[0]]
157
+ u1_trajectory = sol[u[1]]
158
+ ```
159
+
160
+ ### Mixed Vector/Scalar Systems
161
+
162
+ ```python
163
+ # Coupled system with both scalar and vector variables
164
+ x = var("x") # Scalar variable
165
+ u = var("u", shape=2) # Vector variable
166
+
167
+ eqs = [
168
+ Eq(x.d(2) + x - u[0], 0), # x'' + x - u₀ = 0
169
+ Eq(u[0].d() + u[1], x), # u₀' + u₁ = x
170
+ Eq(u[1].d() + u[0], 0), # u₁' + u₀ = 0
171
+ ]
172
+
173
+ ivp = {
174
+ x: 1.0, # x(0) = 1
175
+ x.d(): 0.0, # x'(0) = 0
176
+ u: [0.5, 0.0], # u(0) = [0.5, 0.0]
177
+ u.d(): [0.0, 0.0] # u'(0) = [0.0, 0.0] (automatically filtered for first-order components)
178
+ }
179
+
180
+ sol = solve(eqs, ivp=ivp, tspan=(0, 5), backend="scipy")
181
+ ```
182
+
183
+ ## Examples
184
+
185
+ The `examples/` directory contains comprehensive examples:
186
+
187
+ - `01_ivp_damped_oscillator.py` - Numeric IVP solving with visualization
188
+ - `02_symbolic_simple.py` - Symbolic solutions using SymPy backend
189
+ - `03_mixed_orders.py` - Coupled systems with mixed derivative orders
190
+ - `04_vector_harmonic_oscillator.py` - 2D harmonic oscillator using vector variables
191
+ - `05_vector_mixed_system.py` - Mixed vector/scalar systems
192
+ - `06_vector_simple.py` - Simple vector variable introduction
193
+
194
+ Run any example:
195
+ ```bash
196
+ python examples/01_ivp_damped_oscillator.py
197
+ ```
198
+
199
+ ## Backends
200
+
201
+ ### SciPy (Numeric)
202
+ ```python
203
+ # Solve numerically over a time span
204
+ sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="scipy")
205
+ ```
206
+
207
+ ### SymPy (Symbolic)
208
+ ```python
209
+ # Get exact symbolic solution
210
+ sol = solve(eq, backend="sympy")
211
+ expr = sol.as_expr(y) # Returns SymPy expression
212
+ ```
213
+
214
+ ### Auto Backend Selection
215
+ ```python
216
+ # Try symbolic first, fall back to numeric
217
+ sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="auto")
218
+ ```
219
+
220
+ ## API Reference
221
+
222
+ ### Variables and Equations
223
+ - `var(name, order=None)` - Create a scalar dependent variable
224
+ - `var(name, shape=n)` - Create a vector variable with n components
225
+ - `var(name, shape=(m,n))` - Create a matrix variable (coming soon)
226
+ - `y.d(n)` - n-th derivative of variable y
227
+ - `u[i]` - Access i-th component of vector variable u
228
+ - `u.d(n)` - n-th derivative of vector variable (returns vector derivative)
229
+ - `Eq(lhs, rhs)` - Create an equation
230
+ - `t` - Independent variable (time)
231
+
232
+ ### Solving
233
+ - `solve(equations, ivp=None, bvp=None, tspan=None, backend="auto")`
234
+
235
+ ### Solution Objects
236
+ - `sol[y]` - Access solution values for variable y
237
+ - `sol[y.d()]` - Access derivative values
238
+ - `sol[u]` - Access vector solution (returns 2D array for vector variables)
239
+ - `sol[u[i]]` - Access i-th component solution (returns 1D array)
240
+ - `sol.eval(target, time_points)` - Evaluate at specific times
241
+ - `sol.as_first_order()` - Inspect first-order system representation
242
+
243
+ ## Contributing
244
+
245
+ This project follows a test-driven development approach. All functionality is defined by comprehensive tests.
246
+
247
+ ### Development Setup
248
+ ```bash
249
+ git clone https://github.com/maroba/odecast.git
250
+ cd odecast
251
+ pip install -e ".[dev]"
252
+ ```
253
+
254
+ ### Running Tests
255
+ ```bash
256
+ pytest # Run all tests
257
+ pytest -v # Verbose output
258
+ pytest tests/test_api* # Run specific test files
259
+ ```
260
+
261
+ ### Code Quality
262
+ ```bash
263
+ ruff check . # Linting
264
+ black . # Formatting
265
+ ```
266
+
267
+ ### Contributing Guidelines
268
+ 1. All new features must have comprehensive tests
269
+ 2. Follow the existing API patterns and naming conventions
270
+ 3. Add examples for significant new functionality
271
+ 4. Update documentation for user-facing changes
272
+ 5. Ensure all tests pass before submitting PRs
273
+
274
+ ## Status
275
+
276
+ Current implementation status:
277
+ - ✅ Core DSL (variables, equations, derivatives)
278
+ - ✅ Vector/Matrix variables with automatic equation expansion
279
+ - ✅ SciPy numeric backend (IVP)
280
+ - ✅ SymPy symbolic backend (decoupled systems)
281
+ - ✅ Automatic order inference and validation
282
+ - ✅ Comprehensive error handling
283
+ - ✅ Mixed-order coupled systems
284
+ - 🚧 BVP support (boundary value problems) - coming soon
285
+
286
+ ## License
287
+
288
+ MIT License - see LICENSE file for details.
@@ -0,0 +1,262 @@
1
+
2
+ # <img src="https://github.com/maroba/odecast/raw/main/docs/odecast-logo.png" alt="Odecast Logo" width="120" align="left" />
3
+
4
+ # Odecast
5
+
6
+ [![PyPI version](https://img.shields.io/pypi/v/odecast.svg)](https://pypi.org/project/odecast/)
7
+ [![License](https://img.shields.io/github/license/maroba/odecast)](https://github.com/maroba/odecast/blob/main/LICENSE)
8
+ [![Tests](https://github.com/maroba/odecast/actions/workflows/test.yml/badge.svg)](https://github.com/maroba/odecast/actions)
9
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
10
+
11
+ A Python library for solving higher-order ordinary differential equations (ODEs) without manual reduction. Write equations in natural mathematical form (e.g. `y.d(2) + 0.3*y.d() + y = 0`) and let odecast handle order inference, validation, conversion to first-order systems, and solving via SymPy (symbolic) or SciPy (numeric).
12
+
13
+ ## Features
14
+
15
+ - **Intuitive syntax**: Write ODEs as they appear in textbooks using `y.d(2)` for derivatives
16
+ - **Vector/Matrix variables**: Support for systems with `var("u", shape=2)` and component access `u[0]`, `u[1]`
17
+ - **Multiple backends**: Symbolic solutions via SymPy, numeric solutions via SciPy
18
+ - **Automatic order inference**: No need to manually convert to first-order systems
19
+ - **Automatic equation expansion**: Vector equations automatically expand to component equations
20
+ - **Comprehensive validation**: Clear error messages for missing or inconsistent conditions
21
+ - **Flexible interface**: Support for IVP (initial value problems) and BVP (boundary value problems)
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install -e ".[math,dev]"
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ from odecast import t, var, Eq, solve
33
+
34
+ # Define a variable
35
+ y = var("y")
36
+
37
+ # Create an equation: y'' + 0.3*y' + y = 0 (damped harmonic oscillator)
38
+ eq = Eq(y.d(2) + 0.3*y.d() + y, 0)
39
+
40
+ # Solve with initial conditions y(0) = 1, y'(0) = 0
41
+ sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0.0, 10.0), backend="scipy")
42
+
43
+ # Access solution data
44
+ y_values = sol[y] # Position over time
45
+ velocity = sol[y.d()] # Velocity over time
46
+ times = sol.t # Time points
47
+
48
+ # Evaluate at specific times
49
+ position_at_5s = sol.eval(y, 5.0)
50
+
51
+ # Vector variables for systems
52
+ u = var("u", shape=2) # 2D vector variable
53
+ eq_vector = Eq(u.d(2) + u, 0) # Vector harmonic oscillator
54
+ sol_vector = solve(eq_vector,
55
+ ivp={u: [1.0, 0.0], u.d(): [0.0, 1.0]},
56
+ tspan=(0, 5), backend="scipy")
57
+ positions = sol_vector[u] # 2×N array of [x, y] positions
58
+ ```
59
+
60
+ ## Vector/Matrix Variables
61
+
62
+ Odecast supports vector and matrix variables for systems of equations, making it easy to work with multi-dimensional problems.
63
+
64
+ ### Creating Vector Variables
65
+
66
+ ```python
67
+ from odecast import t, var, Eq, solve
68
+
69
+ # Create a 2D vector variable
70
+ u = var("u", shape=2) # Creates u with components u[0], u[1]
71
+
72
+ # Create a 3D vector variable
73
+ v = var("v", shape=3) # Creates v with components v[0], v[1], v[2]
74
+
75
+ # Matrix variables (coming soon)
76
+ # A = var("A", shape=(2, 2)) # 2x2 matrix
77
+ ```
78
+
79
+ ### Component Access
80
+
81
+ ```python
82
+ u = var("u", shape=2)
83
+
84
+ # Access individual components
85
+ u0 = u[0] # First component
86
+ u1 = u[1] # Second component
87
+
88
+ # Components behave like regular variables
89
+ eq1 = Eq(u[0].d(2) + u[0], 0) # u₀'' + u₀ = 0
90
+ eq2 = Eq(u[1].d() + u[0], 0) # u₁' + u₀ = 0
91
+ ```
92
+
93
+ ### Vector Operations
94
+
95
+ ```python
96
+ u = var("u", shape=2)
97
+
98
+ # Vector derivatives
99
+ u_dot = u.d() # First derivative: [u[0]', u[1]']
100
+ u_ddot = u.d(2) # Second derivative: [u[0]'', u[1]'']
101
+
102
+ # Vector equations automatically expand to component equations
103
+ eq = Eq(u.d(2) + u, 0) # Becomes: u[0]'' + u[0] = 0, u[1]'' + u[1] = 0
104
+
105
+ # Vector arithmetic
106
+ position = var("r", shape=2)
107
+ velocity = var("v", shape=2)
108
+ eq1 = Eq(position.d() - velocity, 0) # r' = v
109
+ eq2 = Eq(velocity.d() + 0.1*velocity, 0) # v' + 0.1v = 0 (damping)
110
+ ```
111
+
112
+ ### Vector Initial Conditions
113
+
114
+ ```python
115
+ u = var("u", shape=2)
116
+ eq = Eq(u.d(2) + u, 0) # 2D harmonic oscillator
117
+
118
+ # Vector-style initial conditions
119
+ ivp = {
120
+ u: [1.0, 0.5], # u(0) = [1.0, 0.5]
121
+ u.d(): [0.0, -0.2] # u'(0) = [0.0, -0.2]
122
+ }
123
+
124
+ sol = solve(eq, ivp=ivp, tspan=(0, 10), backend="scipy")
125
+
126
+ # Access vector solution (returns 2×N array)
127
+ u_trajectory = sol[u] # Shape: (2, num_timepoints)
128
+
129
+ # Access individual components (returns 1D arrays)
130
+ u0_trajectory = sol[u[0]]
131
+ u1_trajectory = sol[u[1]]
132
+ ```
133
+
134
+ ### Mixed Vector/Scalar Systems
135
+
136
+ ```python
137
+ # Coupled system with both scalar and vector variables
138
+ x = var("x") # Scalar variable
139
+ u = var("u", shape=2) # Vector variable
140
+
141
+ eqs = [
142
+ Eq(x.d(2) + x - u[0], 0), # x'' + x - u₀ = 0
143
+ Eq(u[0].d() + u[1], x), # u₀' + u₁ = x
144
+ Eq(u[1].d() + u[0], 0), # u₁' + u₀ = 0
145
+ ]
146
+
147
+ ivp = {
148
+ x: 1.0, # x(0) = 1
149
+ x.d(): 0.0, # x'(0) = 0
150
+ u: [0.5, 0.0], # u(0) = [0.5, 0.0]
151
+ u.d(): [0.0, 0.0] # u'(0) = [0.0, 0.0] (automatically filtered for first-order components)
152
+ }
153
+
154
+ sol = solve(eqs, ivp=ivp, tspan=(0, 5), backend="scipy")
155
+ ```
156
+
157
+ ## Examples
158
+
159
+ The `examples/` directory contains comprehensive examples:
160
+
161
+ - `01_ivp_damped_oscillator.py` - Numeric IVP solving with visualization
162
+ - `02_symbolic_simple.py` - Symbolic solutions using SymPy backend
163
+ - `03_mixed_orders.py` - Coupled systems with mixed derivative orders
164
+ - `04_vector_harmonic_oscillator.py` - 2D harmonic oscillator using vector variables
165
+ - `05_vector_mixed_system.py` - Mixed vector/scalar systems
166
+ - `06_vector_simple.py` - Simple vector variable introduction
167
+
168
+ Run any example:
169
+ ```bash
170
+ python examples/01_ivp_damped_oscillator.py
171
+ ```
172
+
173
+ ## Backends
174
+
175
+ ### SciPy (Numeric)
176
+ ```python
177
+ # Solve numerically over a time span
178
+ sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="scipy")
179
+ ```
180
+
181
+ ### SymPy (Symbolic)
182
+ ```python
183
+ # Get exact symbolic solution
184
+ sol = solve(eq, backend="sympy")
185
+ expr = sol.as_expr(y) # Returns SymPy expression
186
+ ```
187
+
188
+ ### Auto Backend Selection
189
+ ```python
190
+ # Try symbolic first, fall back to numeric
191
+ sol = solve(eq, ivp=conditions, tspan=(0, 10), backend="auto")
192
+ ```
193
+
194
+ ## API Reference
195
+
196
+ ### Variables and Equations
197
+ - `var(name, order=None)` - Create a scalar dependent variable
198
+ - `var(name, shape=n)` - Create a vector variable with n components
199
+ - `var(name, shape=(m,n))` - Create a matrix variable (coming soon)
200
+ - `y.d(n)` - n-th derivative of variable y
201
+ - `u[i]` - Access i-th component of vector variable u
202
+ - `u.d(n)` - n-th derivative of vector variable (returns vector derivative)
203
+ - `Eq(lhs, rhs)` - Create an equation
204
+ - `t` - Independent variable (time)
205
+
206
+ ### Solving
207
+ - `solve(equations, ivp=None, bvp=None, tspan=None, backend="auto")`
208
+
209
+ ### Solution Objects
210
+ - `sol[y]` - Access solution values for variable y
211
+ - `sol[y.d()]` - Access derivative values
212
+ - `sol[u]` - Access vector solution (returns 2D array for vector variables)
213
+ - `sol[u[i]]` - Access i-th component solution (returns 1D array)
214
+ - `sol.eval(target, time_points)` - Evaluate at specific times
215
+ - `sol.as_first_order()` - Inspect first-order system representation
216
+
217
+ ## Contributing
218
+
219
+ This project follows a test-driven development approach. All functionality is defined by comprehensive tests.
220
+
221
+ ### Development Setup
222
+ ```bash
223
+ git clone https://github.com/maroba/odecast.git
224
+ cd odecast
225
+ pip install -e ".[dev]"
226
+ ```
227
+
228
+ ### Running Tests
229
+ ```bash
230
+ pytest # Run all tests
231
+ pytest -v # Verbose output
232
+ pytest tests/test_api* # Run specific test files
233
+ ```
234
+
235
+ ### Code Quality
236
+ ```bash
237
+ ruff check . # Linting
238
+ black . # Formatting
239
+ ```
240
+
241
+ ### Contributing Guidelines
242
+ 1. All new features must have comprehensive tests
243
+ 2. Follow the existing API patterns and naming conventions
244
+ 3. Add examples for significant new functionality
245
+ 4. Update documentation for user-facing changes
246
+ 5. Ensure all tests pass before submitting PRs
247
+
248
+ ## Status
249
+
250
+ Current implementation status:
251
+ - ✅ Core DSL (variables, equations, derivatives)
252
+ - ✅ Vector/Matrix variables with automatic equation expansion
253
+ - ✅ SciPy numeric backend (IVP)
254
+ - ✅ SymPy symbolic backend (decoupled systems)
255
+ - ✅ Automatic order inference and validation
256
+ - ✅ Comprehensive error handling
257
+ - ✅ Mixed-order coupled systems
258
+ - 🚧 BVP support (boundary value problems) - coming soon
259
+
260
+ ## License
261
+
262
+ MIT License - see LICENSE file for details.
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "odecast"
7
+ version = "0.1.0"
8
+ description = "A Python library for solving higher-order ordinary differential equations (ODEs) without manual reduction."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "Matthias Baer", email = "matthias.r.baer@googlemail.com" }]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ ]
22
+ dependencies = []
23
+
24
+ [project.optional-dependencies]
25
+ math = ["sympy", "scipy", "numpy", "matplotlib"]
26
+ dev = ["pytest", "pytest-cov"]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/maroba/odecast"
30
+ Repository = "https://github.com/maroba/odecast"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["src/odecast"]
34
+
35
+ [tool.hatch.build.targets.sdist]
36
+ include = ["/src", "/tests"]
@@ -0,0 +1,10 @@
1
+ """
2
+ Odecast: A DSL for ordinary differential equations
3
+ """
4
+
5
+ from .symbols import t
6
+ from .api import var, solve, BC
7
+ from .equation import Eq
8
+
9
+ __version__ = "0.1.0"
10
+ __all__ = ["t", "var", "Eq", "solve", "BC"]