counting / maths /calculus /multiple_integral.py
spagestic's picture
feat: simplify descriptions and examples in Gradio interfaces for arithmetic and calculus tools
db31576
import sympy
from typing import List, Tuple, Union
import gradio as gr
import json
def multiple_integral(expression_str: str, integration_vars: List[Tuple[str, Union[str, float], Union[str, float]]]) -> str:
"""
Computes definite multiple integrals.
Args:
expression_str: The mathematical expression (e.g., "x*y**2").
integration_vars: A list of tuples, where each tuple contains:
(variable_name_str, lower_bound_str_or_float, upper_bound_str_or_float).
Example: [("x", "0", "1"), ("y", "0", "x")] for integral from 0 to 1 dx of integral from 0 to x dy of (x*y**2).
The order in the list is the order of integration (inner to outer).
Returns:
String representation of the integral result or an error message.
"""
try:
present_symbols = {sym.name: sym for sym in sympy.parse_expr(expression_str, transformations='all').free_symbols}
integration_params_sympy = []
for var_name, lower_bound, upper_bound in integration_vars:
var_sym = present_symbols.get(var_name, sympy.Symbol(var_name))
if var_sym.name not in present_symbols:
present_symbols[var_sym.name] = var_sym
lower_s = sympy.sympify(lower_bound, locals=present_symbols)
upper_s = sympy.sympify(upper_bound, locals=present_symbols)
integration_params_sympy.append((var_sym, lower_s, upper_s))
if not integration_params_sympy:
return "Error: No integration variables specified."
expr = sympy.parse_expr(expression_str, local_dict=present_symbols, transformations='all')
integral_val = sympy.integrate(expr, *integration_params_sympy)
return str(integral_val)
except (sympy.SympifyError, TypeError, SyntaxError) as e:
return f"Error parsing expression, bounds, or variables: {e}. Ensure bounds are numbers or valid expressions."
except Exception as e:
return f"An unexpected error occurred during integration: {e}"
def parse_integration_variables(vars_json_str: str):
"""
Parses a JSON string representing a list of integration variables and their bounds.
Expected format: '[["var1", "lower1", "upper1"], ["var2", "lower2", "upper2"]]
"""
try:
parsed_list = json.loads(vars_json_str)
if not isinstance(parsed_list, list):
raise ValueError("Input must be a JSON list.")
integration_vars = []
for item in parsed_list:
if not (isinstance(item, list) and len(item) == 3):
raise ValueError("Each item in the list must be a sub-list of three elements: [variable_name, lower_bound, upper_bound].")
var, low, upp = item
if not isinstance(var, str):
raise ValueError(f"Variable name '{var}' must be a string.")
if not (isinstance(low, (str, int, float))) or not (isinstance(upp, (str, int, float))):
raise ValueError(f"Bounds for variable '{var}' must be numbers or strings. Got '{low}' and '{upp}'.")
integration_vars.append((str(var), str(low), str(upp)))
return integration_vars
except json.JSONDecodeError:
raise gr.Error("Invalid JSON format for integration variables.")
except ValueError as ve:
raise gr.Error(str(ve))
except Exception as e:
raise gr.Error(f"Unexpected error parsing integration variables: {str(e)}")
multiple_integral_interface = gr.Interface(
fn=lambda expr_str, vars_json_str: multiple_integral(expr_str, parse_integration_variables(vars_json_str)),
inputs=[
gr.Textbox(label="Expression (e.g., x*y**2, 1)", value="x*y"),
gr.Textbox(
label="Integration Variables and Bounds (JSON list of [var, low, upp] tuples, inner to outer)",
value='[["y", "0", "x"], ["x", "0", "1"]]',
info="Example: integral_0^1 dx integral_0^x dy (x*y) is [['y', '0', 'x'], ['x', '0', '1']]"
)
],
outputs="text",
title="Definite Multiple Integral Calculator",
description="Compute multiple integrals.\n\n**Description:**\nThis tool computes definite multiple integrals for a given expression and bounds. The order of variables in the list is inner-most integral first.\n\n**Examples:**\n- Expression: x*y, Variables: [[\"y\", \"0\", \"x\"], [\"x\", \"0\", \"1\"]] → Output: 1/6\n- Expression: x**2, Variables: [[\"x\", \"0\", \"2\"]] → Output: 8/3\n- Expression: 1, Variables: [[\"x\", \"0\", \"1\"], [\"y\", \"0\", \"1\"]] → Output: 1",
examples=[["x*y", '[["y", "0", "x"], ["x", "0", "1"]]'], ["x**2", '[["x", "0", "2"]]'], ["1", '[["x", "0", "1"], ["y", "0", "1"]]']],
)