counting / maths /differential_equations /ode_interface_utils.py
spagestic's picture
feat: modularize differential equations interfaces and add utility functions for parsing and evaluation
3dd583e
"""
Helper functions for parsing and ODE lambda string evaluation for ODE solvers.
"""
import gradio as gr
import numpy as np
from typing import List, Tuple, Callable
import math
def parse_float_list(input_str: str, expected_len: int = 0) -> List[float]:
try:
if not input_str.strip():
if expected_len > 0:
raise ValueError("Input string is empty.")
return []
parts = [float(p.strip()) for p in input_str.split(',') if p.strip()]
if expected_len > 0 and len(parts) != expected_len:
raise ValueError(f"Expected {expected_len} values, but got {len(parts)}.")
return parts
except ValueError as e:
raise gr.Error(f"Invalid format for list of numbers. Use comma-separated floats. Error: {e}")
def parse_time_span(time_span_str: str) -> Tuple[float, float]:
parts = parse_float_list(time_span_str, expected_len=2)
if parts[0] >= parts[1]:
raise gr.Error("t_start must be less than t_end for the time span.")
return (parts[0], parts[1])
def string_to_ode_func(lambda_str: str, expected_args: Tuple[str, ...]) -> Callable:
lambda_str = lambda_str.strip()
if not lambda_str.startswith("lambda"):
raise gr.Error("ODE function must be a Python lambda string (e.g., 'lambda t, y: -y').")
try:
lambda_def_part = lambda_str.split(":")[0]
for arg_name in expected_args:
if arg_name not in lambda_def_part:
raise gr.Error(f"Lambda function string does not seem to contain expected argument: '{arg_name}'. Expected args: {expected_args}")
safe_eval_globals = {
"np": np,
"math": math,
"sin": math.sin, "cos": math.cos, "tan": math.tan,
"exp": math.exp, "log": math.log, "log10": math.log10,
"sqrt": math.sqrt, "fabs": math.fabs, "pow": math.pow,
"pi": math.pi, "e": math.e
}
func = eval(lambda_str, safe_eval_globals, {})
if not callable(func):
raise gr.Error("The provided string did not evaluate to a callable function.")
return func
except SyntaxError as se:
raise gr.Error(f"Syntax error in lambda function: {se}. Ensure it's valid Python syntax.")
except Exception as e:
raise gr.Error(f"Error evaluating lambda function string: {e}. Ensure it's a valid lambda returning the derivative(s).")