From 8d075cbcad4f0cce20766968a4acf3cb520dbb8d Mon Sep 17 00:00:00 2001 From: awais-ur-rehman Date: Sun, 25 Oct 2026 16:39:53 +0500 Subject: [PATCH] docs(examples): add scipy integration case study --- .binder/environment.yml | 1 + docs/use/case_studies/index.md | 6 ++ .../case_studies/scipy_integration.myst.md | 81 +++++++++++++++++++ docs/use/index.md | 1 + symedocs.yml | 1 + 5 files changed, 90 insertions(+) create mode 100644 docs/use/case_studies/index.md create mode 100644 docs/use/case_studies/scipy_integration.myst.md diff --git a/.binder/environment.yml b/.binder/environment.yml index c7e386866..198850f20 100644 --- a/.binder/environment.yml +++ b/.binder/environment.yml @@ -196,6 +196,7 @@ dependencies: - readline=8.0=he28a2e2_2 - requests=2.25.1=pyhd3deb0d_0 - ruby=2.5.7=he592edb_2 + - scipy - send2trash=1.5.0=py_0 - setuptools=49.6.0=py39hf3d152e_3 - shellingham=1.4.0=pyh44b312d_0 diff --git a/docs/use/case_studies/index.md b/docs/use/case_studies/index.md new file mode 100644 index 000000000..da48fed65 --- /dev/null +++ b/docs/use/case_studies/index.md @@ -0,0 +1,6 @@ +# Case Studies + +```{toctree} +:titlesonly: +Numerical integration with SciPy +``` diff --git a/docs/use/case_studies/scipy_integration.myst.md b/docs/use/case_studies/scipy_integration.myst.md new file mode 100644 index 000000000..bed532532 --- /dev/null +++ b/docs/use/case_studies/scipy_integration.myst.md @@ -0,0 +1,81 @@ +--- +jupytext: + formats: ipynb,md:myst + text_representation: + extension: .md + format_name: myst + format_version: 0.12 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +# Numerical integration with SciPy + +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/Symengine/symengine.github.io/sources?filepath=docs/use/case_studies/scipy_integration.myst.md) +[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Symengine/symengine.github.io/blob/notebooks/use/case_studies/scipy_integration.myst.ipynb) +[![Local Installation](https://img.shields.io/badge/Local-Instructions-orange)](../tutorial.md) + +SciPy's numerical integrators accept Python functions, but they can also call a +compiled SymEngine expression through a low-level callback. This example evaluates +the same double integral both ways and checks the result against its exact value. + +Install SciPy in the [tutorial environment](../tutorial.md) before running the cells: + +```bash +conda install scipy +``` + +## Define the integrand + +```{code-cell} ipython3 +import math + +import symengine as se +from scipy import integrate + +t, x = se.symbols("t x") +expression = se.exp(-x * t) / t**5 +``` + +We integrate over $1 \leq t < \infty$ and $0 \leq x < \infty$. +Integrating with respect to $x$ first gives $t^{-6}$, whose integral from +$1$ to $\infty$ is $1/5$. + +## Compile a SciPy callback + +Pass `as_scipy=True` to `Lambdify` to obtain a callback that SciPy can use +directly. The order of the symbols must match the order of the integration +ranges: here `t` is the innermost variable and `x` is the outermost variable. + +```{code-cell} ipython3 +compiled = se.Lambdify([t, x], [expression], as_scipy=True) +ranges = [[1, math.inf], [0, math.inf]] +compiled_value, compiled_error = integrate.nquad(compiled, ranges) +assert math.isclose(compiled_value, 0.2, rel_tol=0, abs_tol=1e-7) +compiled_value, compiled_error +``` + +The second returned value is SciPy's estimate of the absolute integration error. +The callback evaluates the compiled expression without calling a Python function +for each integrand evaluation. + +## Compare with a Python function + +```{code-cell} ipython3 +def python_integrand(t, x): + return math.exp(-x * t) / t**5 + + +python_value, python_error = integrate.nquad(python_integrand, ranges) +assert math.isclose(python_value, 0.2, rel_tol=0, abs_tol=1e-7) +assert math.isclose(compiled_value, python_value, rel_tol=0, abs_tol=1e-7) +python_value, python_error +``` + +Both calls use the same integration ranges and default tolerances. To compare +timings locally, construct `compiled` once before measuring repeated integration +calls; compiling the expression is a separate cost. The benefit depends on the +expression and the number of integrand evaluations, so this example does not +assume a fixed speedup. diff --git a/docs/use/index.md b/docs/use/index.md index 3a5b7a4eb..3a9956d5e 100644 --- a/docs/use/index.md +++ b/docs/use/index.md @@ -5,4 +5,5 @@ The reader is expected to engage with the material in the [API exploration](api/ :titlesonly: Following Along API Exploration +Case Studies ``` diff --git a/symedocs.yml b/symedocs.yml index 53450bda6..a6f507642 100644 --- a/symedocs.yml +++ b/symedocs.yml @@ -17,6 +17,7 @@ dependencies: - python=3.9.1 - python-symengine=0.6.1 - ruby=2.5.7 + - scipy - sphinx=3.4.3 - sphinx-autobuild - sphinx-copybutton