diff --git a/.github/actions/nbmake/action.yaml b/.github/actions/nbmake/action.yaml index 06076092..ea2d5e09 100644 --- a/.github/actions/nbmake/action.yaml +++ b/.github/actions/nbmake/action.yaml @@ -22,6 +22,7 @@ runs: pytest --junitxml=report-pytest-nbmake-$result.xml -vvv --nbmake "${{ inputs.dir }}" echo "outfile=$result" >> $GITHUB_OUTPUT - name: Upload the report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ./report-pytest-nbmake-${{ steps.execute.outputs.outfile }}.xml + name: report-pytest-nbmake-${{ steps.execute.outputs.outfile }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a7b9876d..2c4ebed3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -24,7 +24,7 @@ jobs: - name: Upload the report uses: actions/upload-artifact@v4 with: - name: report-pytest-with-numba.xml + name: report-pytest-with-numba path: ./report-pytest-with-numba.xml tests-without-numba: @@ -44,7 +44,7 @@ jobs: - name: Upload the report uses: actions/upload-artifact@v4 with: - name: report-pytest-without-numba.xml + name: report-pytest-without-numba path: ./report-pytest-without-numba.xml - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 @@ -95,9 +95,10 @@ jobs: - name: Build the wheel run: python -m build --wheel - name: Upload the wheel - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ./dist/*.whl + name: wheel build-sdist: name: Build sdist on latest Linux @@ -112,6 +113,7 @@ jobs: - name: Build the source distribution run: python -m build --sdist - name: Upload the wheel - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: ./dist/*.tar.gz + name: sdist diff --git a/.github/workflows/docs-preview.yaml b/.github/workflows/docs-preview.yaml index a556be3b..23f3183c 100644 --- a/.github/workflows/docs-preview.yaml +++ b/.github/workflows/docs-preview.yaml @@ -25,6 +25,8 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v4 + with: + fetch-depth: 0 # important: gets all history and tags - name: Install Minterpy with docs extras uses: ./.github/actions/install-minterpy with: diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 8b313685..44793570 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -18,6 +18,8 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v4 + with: + fetch-depth: 0 # important: gets all history and tags - name: Install Minterpy with docs extras uses: ./.github/actions/install-minterpy with: diff --git a/AUTHORS.md b/AUTHORS.md index afca7e3a..f75fe73b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,26 +2,31 @@ ## Main code development -- Damar Wicaksono (HZDR/CASUS) -- Uwe Hernandez Acosta (HZDR/CASUS) -- Sachin Krishnan Thekke Veettil (HZDR/CASUS) +- [Damar Wicaksono](https://orcid.org/0000-0001-8587-7730) ([HZDR]/ [CASUS](https://www.casus.science/?page_id=4528)) +- [Uwe Hernandez Acosta](https://orcid.org/0000-0002-6182-1481) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4442)) +- [Janina Schreiber](https://orcid.org/0000-0002-8692-0822) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4528)) ## Mathematical foundation -- Michael Hecht(HZDR/CASUS) +- [Michael Hecht](https://orcid.org/0000-0001-9214-8253) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4528)) -## Former Members and Contributions +## Former members and contributors -- Jannik Michelfeit -- Nico Hoffman (HZDR) -- Steve Schmerler (HZDR) -- Vidya Chandrashekar (TU Dresden) +- [Sachin Krishnan Thekke Veettil](https://orcid.org/0000-0003-4852-2839) +- [Jannik Kissinger](https://orcid.org/0000-0002-1819-6975) +- [Nico Hoffman](https://scholar.google.de/citations?user=8iDQeTwAAAAJ&hl=de) +- [Steve Schmerler](https://orcid.org/0000-0003-1354-0578) ([HZDR]) +- Vidya Chandrashekar ([TU Dresden](https://tu-dresden.de/)) -## Acknowledgement +## Acknowledgements -- Klaus Steiniger (HZDR) -- Patrick Stiller (HZDR) -- Matthias Werner (HZDR) -- Krzysztof Gonciarz (MPI-CBG,CSBD) -- Attila Cangi (HZDR/CASUS) -- Michael Bussmann (HZDR/CASUS) +- [Klaus Steiniger](https://orcid.org/0000-0001-8965-1149) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4353)) +- [Patrick Stiller](https://scholar.google.com/citations?user=nOtYbWMAAAAJ&hl=de) ([HZDR]) +- Matthias Werner ([HZDR]) +- [Krzysztof Gonciarz](https://orcid.org/0000-0001-9054-8341) ([MPI-CBG]/[CSBD]) +- [Attila Cangi](https://orcid.org/0000-0001-9162-262X) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4660)) +- [Michael Bussmann](https://orcid.org/0000-0002-8258-3881) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4353)) + +[HZDR]: https://www.hzdr.de +[MPI-CBG]: https://www.mpi-cbg.de +[CSBD]: https://www.csbdresden.de diff --git a/CHANGELOG.md b/CHANGELOG.md index cc39af04..199474be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Changelog -## Version 0.3.0 +All notable changes to the Minterpy project is documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [Version 0.3.1] - 2025-04-30 + +This minor release incorporates feedback from the review process of +the Minterpy submission to the Journal of Open Source Software (JOSS). +There are no changes to the package's functionality. + +### Added + +- Included the source code and manuscript for the JOSS paper in the repository. + +### Changed + +- Revised and updated several documentation components, including `README.md`, + `CONTRIBUTING.md`, and the Getting Started guides. + +## Version 0.3.0 - 2024-12-20 ### Added @@ -171,7 +193,7 @@ coupling with the Newton polynomial class and the corresponding transformation class. -# Version 0.2.0-alpha +# Version 0.2.0-alpha - 2023-01-06 This is the next alpha release of `minterpy`, which adds several new functionalities and enhances code quality and performance. @@ -209,3 +231,6 @@ in multiple dimensions: This code is still highly experimental and there is no assurance, that neither everything works as expected, nor if further releases will break the current API. + +[Unreleased]: https://github.com/minterpy-project/minterpy/compare/main...dev +[0.3.1]: https://github.com/minterpy-project/minterpy/compare/v0.3.0...v0.3.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1717d986..47558f6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,36 +1,38 @@ # Contribution Guide -Thanks a lot for your interest and taking the time to contribute to the `minterpy` project! +Thanks a lot for your interest and taking the time to contribute +to the Minterpy project! -This document provides guidelines for contributing to the `minterpy` project. +This document provides short guidelines for contributing +to the Minterpy project. +For a more comprehensive guide, please refer to the online documentation +([stable](https://minterpy-project.github.io/minterpy/stable/contributors/index.html) +or [latest](https://minterpy-project.github.io/minterpy/latest/contributors/index.html)) ## Installation This installation guide is focused on development. -For installing `minterpy` in production runs check out the [README.md](./README.md). +For installing Minterpy in production environment, check out [README.md](./README.md). -In order to get the source of latest release, -clone the `minterpy` repository from the [HZDR GitLab]: +### Obtaining the source -```bash -git clone https://gitlab.hzdr.de/interpol/minterpy.git -``` - -By default, the cloned branch is the `main` branch. - -To get the latest development version, checkout to the `dev` branch: +To obtain the latest source, +clone the Minterpy repository from [GitHub](https://github.com/minterpy-project/minterpy): ```bash -git checkout dev +git clone https://github.com/minterpy-project/minterpy ``` -We recommend to always pull the latest commit: +By default, the cloned branch is the `dev` branch (i.e., the latest development +version). + +We recommend always pulling the latest commit: ```bash git pull origin dev ``` -You are not allowed to directly push to `dev` or `master` branch. +You are not allowed to directly push to `dev` or `main` branch. Please follow the instructions under [Branching workflow](#branching-workflow). ### Virtual environments @@ -39,7 +41,7 @@ Following a best practice in Python development, we strongly encourage you to create and use virtual environments for development and production runs. A virtual environment encapsulates the package and all dependencies without messing up your other Python installations. -The following instructions should be executed from the `minterpy` source directory. +The following instructions should be executed from the Minterpy source directory. #### Using [venv](https://docs.python.org/3/tutorial/venv.html) from the python standard library: @@ -49,7 +51,7 @@ The following instructions should be executed from the `minterpy` source directo python -m venv ``` - Replace `` with an environment name of your choice. + Replace `` with an environment name of your choice. 2. Activate the environment you just created: @@ -57,12 +59,10 @@ The following instructions should be executed from the `minterpy` source directo source /bin/activate ``` - as before replace `` with the environment name. - + Replace with your desired environment name. 3. To deactivate the virtual environment, type: - ```bash deactivate ``` @@ -75,19 +75,18 @@ The following instructions should be executed from the `minterpy` source directo virtualenv ``` - Replace `` with an environment name of your choice. + Replace `` with an environment name of your choice. -2. Activate the environment: +2. Activate the environment you just created: ```bash source /bin/activate ``` - As before replace `` with the environment name. + Replace with your desired environment name. 3. To deactivate the virtual environment, type: - ```bash deactivate ``` @@ -100,17 +99,18 @@ The following instructions should be executed from the `minterpy` source directo pyenv virtualenv 3.8 ``` - Replace `` with an environment name of your choice. + Replace `` with an environment name of your choice. -2. Activate the newly created environment in the current local directory: +2. Activate the environment you just created: ```bash pyenv local ``` - As before replace `` with the environment name. + Replace with your desired environment name. - The above command creates a hidden file `.python_version` containing a "link" to the actual virtual environment managed by `pyenv`. + This command creates a hidden `.python_version` file containing + a "link" to the actual virtual environment managed by `pyenv`. 3. To "deactivate" the virtual environment just remove this hidden file: @@ -127,6 +127,7 @@ The following instructions should be executed from the `minterpy` source directo ```bash conda env create -f environment.yaml ``` + The command creates a new conda environment called `minterpy`. 2. Activate the new environment with: @@ -147,9 +148,9 @@ The following instructions should be executed from the `minterpy` source directo ### Installation We recommend using [pip](https://pip.pypa.io/en/stable/) from within a virtual environment (see above) -to install `minterpy`. +to install Minterpy. -To install `minterpy`, type: +To install Minterpy from source, type: ```bash pip install [-e] .[all,dev,docs] @@ -158,7 +159,7 @@ pip install [-e] .[all,dev,docs] where the flag `-e` means the package is directly linked into the Python site-packages. The options `[all,dev,docs]` refer to the requirements defined in the `options.extras_require` section in `setup.cfg`. -You **must not** use `python setup.py install`, +**Note**: **Do not** use `python setup.py install`, since the file `setup.py` will not be present for every build of the package. ### Troubleshooting: pytest with venv (*not* conda) @@ -174,11 +175,12 @@ deactivate && source /bin/activate or run `hash -r` instead. -This problem does not seem to appear for virtual environments created by conda. +This issue does not seem to occur for environments created by Conda. -### Dependency Management & Reproducibility (conda) +### Dependency management & reproducibility (conda) -Here are a few recommendations for managing dependency and maintaining the reproducibility of your `minterpy` development environment: +Here are some recommendations for managing dependency +and maintaining reproducibility of your Minterpy development environment: 1. Always keep your abstract (unpinned) dependencies updated in `environment.yaml` and eventually in `setup.cfg` if you want to ship and install your package via `pip` later on. @@ -200,13 +202,7 @@ Here are a few recommendations for managing dependency and maintaining the repro ## Testing -:construction: :construction: :construction: :construction: :construction: :construction: :construction: :construction: -Since the whole test environment needs a refactoring, we shall update this section with more detailed informations. -:construction: :construction: :construction: :construction: :construction: :construction: :construction: :construction: - -### Running the unit tests - -We use [pytest](https://docs.pytest.org/en/6.2.x/) to run the unit tests of `minterpy`. +We use [pytest](https://docs.pytest.org/en/6.2.x/) to run the unit tests of Minterpy. The unit tests themselves must always be placed into the `tests` directory. To run all tests, type: @@ -214,7 +210,7 @@ To run all tests, type: pytest ``` -from within the `minterpy` source directory. +from within the Minterpy source directory. If you want to run the tests of a particular module, for instance the `multi_index_utils.py` module, execute: @@ -223,7 +219,7 @@ for instance the `multi_index_utils.py` module, execute: pytest tests/test_multi_index_utils.py ``` -When you run `pytest`, the coverage test is also done automatically. +When running `pytest`, the coverage tests are automotically performed. A summary of the coverage test is printed out in the terminal. Furthermore, you can find an HTML version of the coverage test results in `htmlcov/index.html`. @@ -232,15 +228,13 @@ in `htmlcov/index.html`. We strongly encourage you to use the capabilities of `pytest` for writing the unit tests -It is highly recommended to use the capabilities of `pytest` for writing unittests. - Be aware of the following points: - the developer of the code should write the tests - test the behavior you expect from your code, not breaking points - use as small samples as possible - unit tests do *not* test if the code works, they test if the code *still* works -- the coverage shall always be as high as possible +- the coverage should always be as high as possible - BUT, even 100% coverage does not mean, there is nothing missed (buzz: edge case!) For additional reference on how to write tests, have a look at the following resources: @@ -251,20 +245,19 @@ For additional reference on how to write tests, have a look at the following res ## Documentation -This section provides some information about contributing to the docs. +This section provides some information about building and contributing +to the documentation. ### Install dependencies -Building the docs requires additional dependencies. -If you follow the above installation steps, the dependencies are satisfied. -Otherwise you need to install them separately via: +Building the documentation requires additional dependencies. +You can install Minterpy from source with all the dependencies for building +the documentation as follows: ```bash pip install .[docs] ``` -from the `minterpy` source directory. - ### Building the documentation We use [sphinx](https://www.sphinx-doc.org/en/master/) to build the `minterpy` docs. @@ -274,7 +267,7 @@ To build the docs in HTML format, run the following command: sphinx-build -M html docs docs/build ``` -Alternatively you can build the docs using the supplied Makefile. +Alternatively, you can build the documentation using the supplied Makefile. For that, you need to navigate to the `docs` directory and run the `make` command in Linux/mac OS or `make.bat` in Windows: ```bash @@ -294,35 +287,33 @@ make latexpdf The command builds the docs as a PDF document and stores it along with all the LaTeX source files in `docs/build/latex`. -### Design of the docs +### Documentation source organization -The source files for the docs are stored in the `docs` directory. -The Sphinx configuration file is `docs/conf.py` +The source files for the documentation are stored in the `docs` directory. +The Sphinx configuration file is `docs/conf.py`, and the main index file of the docs is `docs/index.rst`. -The docs itself contains five different main sections: +You can find more information about the Minterpy documentation +in the Contributors Guide ( +[stable](https://minterpy-project.github.io/minterpy/stable/contributors/contrib-docs/index.html) +or [latest](https://minterpy-project.github.io/minterpy/latest/contributors/contrib-docs/index.html)). -- The Getting Started Guide or tutorials (`docs/getting-started`) contains all the tutorials of `minterpy`. -- The How-to Guides (`docs/how-to`) contains the Jupyter notebooks of instructions on how to achieve common tasks with `minterpy`. -- The Fundamentals (`docs/fundamentals`) contains all the explanations on the mathematical background that underlies `minterpy`. -- The Contributors Guide (`docs/contributors`) contains the information on how to contribute to the `minterpy` project, - be it to its development or to its docs. -- The API Reference (`docs/api`) contains the reference to all exposed components of `minterpy` (functions, classes, etc.). +## Code style -You can find more information about the `minterpy` docs in the Contributors Guide. - -## Code Style - -To ensure the readability of the codebase, we are following a common code style for `minterpy`. +To ensure the readability of the codebase, +we are following a common code style for Minterpy. Our long-term goal is to fulfill the [PEP8](https://www.python.org/dev/peps/pep-0008/) regulations. For the build system, it is recommended to follow [PEP517](https://www.python.org/dev/peps/pep-0517/) and [PEP518](https://www.python.org/dev/peps/pep-0518/). -However, since these requirements are very challenging, we use [black](https://github.com/psf/black) to enforce the code style of `minterpy`. +However, since these requirements are very challenging, +we use [black](https://github.com/psf/black) to enforce the code style of Minterpy. During the development process, you can check the format using [pre-commit](https://pre-commit.com) (see below) and -In the development process, one can check the format using and the hooks defined in `.pre-commit-config.yaml`. For instance running `black` for the whole `minterpy` code, just run +In the development process, one can check the format using +and the hooks defined in `.pre-commit-config.yaml`. +For instance running `black` for the whole `minterpy` code, just run ```bash pre-commit run black --all-files @@ -332,10 +323,10 @@ For now, it is recommended to run single hooks. ## Pre-commit -For further developments, it is recommended to run all pre-commit-hooks every time -before committing some changes to your branch. +For on-going developments, it is recommended to run all pre-commit-hooks +every time before committing some changes to your branch. -To enable this, type: +Install the pre-commit hooks by running: ```bash pre-commit install @@ -356,7 +347,7 @@ pre-commit run --all-files # DON'T DO THIS IF YOU DON'T KNOW WHAT HAPPENS In the current state of the code, you should use this with caution since it might change code in the manner that it breaks (see below). -Down the road, we shall try to fulfill the full set of pre-commit hoos. +Down the road, we shall try to fulfill the full set of pre-commit hooks. However, further developments shall try to fulfil the full set of pre-commit-hooks. ### Currently defined hooks @@ -368,7 +359,7 @@ The following hooks are defined: - [pre-commit-hooks](https://github.com/pre-commit/pre-commit-hooks): A collection of widely used hooks; see their repository for more informations. - [isort](https://github.com/PyCQA/isort): sorts the import statements; - changes the code !!!DO NOT RUN THIS: IT WILL BREAK THE CURRENT VERSION!!! + changes the code (**NOTE**: **Do not** run and commit the changes; it may break the current version.) - [pyupgrade](https://github.com/asottile/pyupgrade): convert the syntax from Python2 to Python3. It's nice if you use code from an old post in stackoverflow ;-) - [setup-cfg-fmt](https://github.com/asottile/setup-cfg-fmt): formats the `setup.cfg` file for consistency. @@ -381,24 +372,27 @@ The following hooks are defined: This ensures proper builds for uploading the package to [PyPI](https://pypi.org). This is configured in `setup.cfg[check-manifest]`. +In case you're using pre-commit hooks, be sure to run the test again before +committing or pushing any changes. + ## Code development ### Version control -We only use [git](https://git-scm.com/) to version control `minterpy`. -The main repository for development is place on [HZDR GitLab](https://gitlab.hzdr.de/interpol/minterpy). -Moreover, the releases and the development branch are also mirrored into the [CASUS GitHub](https://github.com/casus/) repository. +We only use [git](https://git-scm.com/) to version control Minterpy. +The main repository for development is +on [GitHub](https://github.com/minterpy-project/minterpy). +Moreover, the releases and the development branch +are also mirrored into the [CASUS GitHub](https://github.com/casus/minterpy) repository. -We are currently considering to upload the builds of `minterpy` to [PyPI](https://pypi.org) and [conda-forge](https://conda-forge.org) -to make the code more accessible. +The latest release of Minterpy is available in [PyPI](https://pypi.org/project/minterpy/). -### Branching workflow +### Branching workflow -We loosely follow the structure of [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) -for our branching workflow. +We follow the structure of [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) for our branching workflow. There are three types of branches in this workflow: -1. `master` branch: +1. `main` branch: On this branch, only the releases are stored. This means, on this branch, one has only fully tested, documented and cleaned up code. 2. `dev` branch: @@ -406,46 +400,50 @@ There are three types of branches in this workflow: At any given time, the branch must pass all the tests. This also means that on this branch, there is always a running version of `minterpy` even if the code and the docs are not in a "release state." - 3. `feature` branches: On these branches, all the features and code developments happen. - These branches must always be branched from the `dev` branch (not from `master`). + `feature` branches must be created from the `dev` branch (not from `main`). Based on this workflow, you can freely push, change, and merge *only* on the `feature` branches. Furthermore, your feature branch is open to every developers in the `minterpy` project. Once the implementation of a feature is finished, -you can merge the `feature` branch to the `dev` branch via a merge request. -The project maintainers will merge your merge request once the request is reviewed. +you can merge the `feature` branch to the `dev` branch via a pull request. +The project maintainers will merge your pull request once the request is reviewed. In general, you cannot merge your `feature` branch directly to the `dev` branch. -Furthermore, as a contributor, you cannot merge directly to the `master` branch and you cannot make a merge request for that. -Only the project maintainers can merge the `dev` to the `master` branch following the release procedure -of [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). +Furthermore, as a contributor, you cannot merge directly to the `main` branch +and you cannot make a pull request for that. +Only the project maintainers can merge the `dev` to the `main` branch +following the release procedure of [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). -We manage the bug fixes on every branch separately with the relevant developers, usually via `hotfix` branches to implement the patches. +We manage the bug fixes on every branch separately with the relevant developers, +usually via `hotfix` branches to implement the patches. -In the future, we may set up a continuous integration and development (CI/CD) on [HZDR GitLab](https://gitlab.hzdr.de/interpol/minterpy). +More details can be found in the online documentation +([stable](https://minterpy-project.github.io/minterpy/stable/contributors/development-environment.html#about-the-branching-model) +or [latest](https://minterpy-project.github.io/minterpy/latest/contributors/development-environment.html#about-the-branching-model)) -## Project Organization + +## Source organization ``` +├── .gitignore <- ignored files/directories if `git add/commit` +├── .pre-commit-config.yaml <- Configuration of pre-commit git hooks. ├── AUTHORS.md <- List of developers and maintainers. ├── CHANGELOG.md <- Changelog to keep track of new features and fixes. +├── CONTRIBUTING.md <- Contribution guidelines (this file). +├── environment.yaml <- The conda environment file for reproducibility. ├── LICENSE <- License as chosen on the command-line. +├── MANIFEST.in <- Keep track of (minimal) source distribution files +├── pyproject.toml <- Specification build requirements ├── README.md <- The top-level README for developers. -├── docs <- Directory for Sphinx documentation in rst or md. -├── environment.yaml <- The conda environment file for reproducibility. ├── setup.cfg <- Declarative configuration of your project. ├── setup.py <- Use `python setup.py develop` to install for development or | or create a distribution with `python setup.py bdist_wheel`. +├── .github <- scripts for GitHub actions. +├── docs <- Directory for Sphinx documentation in rst or md. ├── src │ └── minterpy <- Actual Python package where the main functionality goes. -├── tests <- Unit tests which can be run with `py.test`. -├── pyproject.toml <- Specification build requirements -├── MANIFEST.in <- Keep track of (minimal) source distribution files -├── CONTRIBUTING.md <- Contribution guidelines. -├── .readthedocs.yml <- Configuration of readthedocs support -├── .gitignore <- ignored files/directories if `git add/commit` -└── .pre-commit-config.yaml <- Configuration of pre-commit git hooks. +└── tests <- Unit tests which can be run with `pytest`. ``` diff --git a/README.md b/README.md index 85cef7b7..c19fbe0c 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,37 @@ ![](./docs/assets/Wordmark-color.png) [![DOI](https://rodare.hzdr.de/badge/DOI/10.14278/rodare.2062.svg)](https://rodare.hzdr.de/record/2062) +[![status](https://joss.theoj.org/papers/96208a133980e518cdfdc36abdc504de/status.svg)](https://joss.theoj.org/papers/96208a133980e518cdfdc36abdc504de) [![Code style: black][black-badge]][black-link] [![License](https://img.shields.io/github/license/minterpy-project/minterpy)](https://choosealicense.com/licenses/mit/) [![PyPI](https://img.shields.io/pypi/v/minterpy)](https://pypi.org/project/minterpy/) -# Minterpy +# Minterpy: Multivariate Polynomial Interpolation in Python | Branches | Status | | :-----------------------------------------------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`main`](https://github.com/minterpy-project/minterpy/tree/main) (stable) | [![Build](https://github.com/minterpy-project/minterpy/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/minterpy-project/minterpy/actions/workflows/build.yaml?query=branch%3Amain+) [![codecov](https://codecov.io/gh/minterpy-project/minterpy/branch/main/graph/badge.svg?token=J8RCUGRKW3)](https://codecov.io/gh/minterpy-project/minterpy) [![Documentation Build and Deployment](https://github.com/minterpy-project/minterpy/actions/workflows/docs.yaml/badge.svg?branch=main)](https://minterpy-project.github.io/minterpy/stable/) | | [`dev`](https://github.com/minterpy-project/minterpy/tree/dev) (latest) | [![Build](https://github.com/minterpy-project/minterpy/actions/workflows/build.yaml/badge.svg?branch=dev)](https://github.com/minterpy-project/minterpy/actions/workflows/build.yaml?query=branch%3Adev) [![codecov](https://codecov.io/gh/minterpy-project/minterpy/graph/badge.svg?token=J8RCUGRKW3)](https://codecov.io/gh/minterpy-project/minterpy) [![Documentation Build and Deployment](https://github.com/minterpy-project/minterpy/actions/workflows/docs.yaml/badge.svg?branch=dev)](https://minterpy-project.github.io/minterpy/latest/) | -Minterpy is an open-source Python package designed for constructing and manipulating multivariate interpolating polynomials +Minterpy is an open-source Python package designed for constructing +and manipulating multivariate interpolating polynomials with the goal of lifting the curse of dimensionality from interpolation tasks. -Minterpy is being continuously extended and improved, with new functionalities added to address the bottlenecks involving +Minterpy is being continuously extended and improved, +with new functionalities added to address the bottlenecks involving interpolations in various computational tasks. ## Installation -You can obtain the stable release of Minterpy directly from PyPI using `pip`: +You can obtain the stable release of Minterpy directly +from [PyPI](https://pypi.org/project/minterpy/) using `pip`: ```bash pip install minterpy ``` -Alternatively, you can also obtain the latest version of Minterpy from the GitHub repository: +Alternatively, you can also obtain the latest version of Minterpy +from the [GitHub repository](https://github.com/minterpy-project/minterpy): ```bash git clone https://github.com/minterpy-project/minterpy @@ -38,137 +43,183 @@ Then from the source directory, you can install Minterpy: pip install [-e] .[all,dev,docs] ``` -where the flag `-e` means the package is directly linked -into the python site-packages of your Python version. +where the flag `-e` means the package is directly linked into +the python site-packages of your Python version. The options `[all,dev,docs]` refer to the requirements defined in the `options.extras_require` section in `setup.cfg`. -A best practice is to first create a virtual environment with -the help of a tool like [mamba], [conda], [venv], [virtualenv] or [pyenv-virtualenv]. +A best practice is to first create a virtual environment with the help of +a tool like [mamba], [conda], [venv], [virtualenv] or [pyenv-virtualenv]. See [CONTRIBUTING.md](./CONTRIBUTING.md) for details. -**NOTE**: You **must not** use the command `python setup.py install` to install `minterpy`, -as we cannot guarantee that the file `setup.py` will always be present -in the further development of `minterpy`. +**NOTE**: **Do not** use the command `python setup.py install` +to install Minterpy, as we cannot guarantee that the file `setup.py` +will always be present in the further development of Minterpy. ## Quickstart -With `minterpy` one can easily interpolate a given function. -For instance, take the function `f(x) = x\sin(10x)` in one dimension: +Using Minterpy, you can easily interpolate a given function. +For instance, take the one-dimensional function $`f(x) = x \, \sin{(10x)}`$ +with $x \in [-1, 1]$: ```python - import numpy as np +import numpy as np - def test_function(x): - return x * np.sin(10*x) +def test_function(x): + return x * np.sin(10*x) ``` -In order to `minterpy` the function `test_function` -one can use the top-level function `interpolate`: +To interpolate the function, you can use the top-level function `interpolate()`: ```python - import minterpy as mp +import minterpy as mp - interpolant = mp.interpolate(test_function,spatial_dimension=1, poly_degree=64) +interpolant = mp.interpolate(test_function, spatial_dimension=1, poly_degree=64) ``` -Here, interpolant is a callable function, -which can be used as a representation of `test_function`. -`interpolate` takes as arguments the function to interpolate, +`interpolate()` takes as arguments the function to interpolate, the number of dimensions (`spatial_dimension`), -and the degree of the underlying polynomial (`poly_degree`). - +and the degree of the underlying polynomial interpolant (`poly_degree`). You may adjust this parameter in order to get higher accuracy. -For the example above, a degree of 64 produces an interpolant that reproduces -the `test_function` almost up to machine precision: +The resulting `interpolant` is a Python callable, +which can be used as an approximation of `test_function`. + +In this example, an interpolating polynomial of degree $64$ produces +an approximation of `test_function` to near machine precision: ```python - import matplotlib.pylab as plt +import matplotlib.pyplot as plt - x = np.linspace(-1,1,100) +xx = np.linspace(-1, 1, 150) - plt.plot(x,interpolant(x),label="interpolant") - plt.plot(x,test_function(x),"k.",label="test function") - plt.legend() - plt.show() +plt.plot(xx, interpolant(xx), label="interpolant") +plt.plot(xx, test_function(xx), "k.",label="test function") +plt.legend() +plt.show() ``` -Compare test function with its interpolant +Compare test function with its interpolating polynomial -For more comprehensive examples, see the [getting started guides](https://interpol.pages.hzdr.de/minterpy/getting-started/index.html) -section of the `minterpy` docs. +Minterpy's capabilities extend beyond function approximation; +by accessing the underlying interpolating polynomials, +you can carry out common numerical operations on the approximations +like multiplication and differentiation: -## Testing +```python +# Access the underlying Newton interpolating polynomial +nwt_poly = interpolant.to_newton() +# Multiply the polynomial -> obtained another polynomial +prod_poly = nwt_poly * nwt_poly +# Differentiate the polynomial once -> obtained another polynomial +diff_poly = nwt_poly.diff(1) +# Reference function for the (once) differentiated test function +diff_fun = lambda xx: np.sin(10 * xx) + xx * 10 * np.cos(10 * xx) + +fig, axs = plt.subplots(1, 2, figsize=(10, 5)) + +axs[0].plot(xx, prod_poly(xx), label="product polynomial") +axs[0].plot(xx, fun(xx)**2, "k.", label="product test function") +axs[0].legend() +axs[0].set_xlabel("$x$") +axs[0].set_ylabel("$y$") +axs[1].plot(xx, diff_poly(xx), label="differentiated polynomial") +axs[1].plot(xx, diff_fun(xx), "k.", label="differentiated test function") +axs[1].legend() +axs[1].set_xlabel("$x$") + +plt.show() +``` -After installation, we encourage you to at least run the unit tests of `minterpy`, -where we use [`pytest`](https://docs.pytest.org/en/6.2.x/) to run the tests. +Product and differentiated polynomial -If you want to run all tests, type: +The [Getting Started Guides](https://minterpy-project.github.io/minterpy/latest/getting-started/index.html#what-s-next) +provide more examples on approximating functions and performing operations +on interpolating polynomials, including multidimensional cases. -```bash -pytest [-vvv] -``` +## Getting help + +For detailed guidance, +please refer to the online documentation ([stable](https://minterpy-project.github.io/minterpy/stable/) +or [latest](https://minterpy-project.github.io/minterpy/stable/)). +It includes detailed installation instructions, usage examples, API references, +and contributors guide. -from within the `minterpy` source directory. +For any other questions related to the package, +feel free to post your questions on the GitHub repository +[Issue page](https://github.com/minterpy-project/minterpy/issues). -## Contributing to `minterpy` +## Contributing to Minterpy + +Contributions to Minterpy are welcome! -Contributions to the `minterpy` packages are highly welcome. We recommend you have a look at the [CONTRIBUTING.md](./CONTRIBUTING.md) first. -For a more comprehensive contribution guide visit -the [Contributors section](link-to-developer-section) of the documentation. +For a more comprehensive guide visit +the [Contributors Guide](https://minterpy-project.github.io/minterpy/latest/contributors/index.html) +of the documentation. + +## Citing Minterpy + +If you use Minterpy in your research or projects, +please consider citing the archived version +in [RODARE](https://rodare.hzdr.de/record/3354). + +The citation for the current public version is: + +```bibtex +@software{Minterpy_0_3_0, + author = {Hernandez Acosta, Uwe and Thekke Veettil, Sachin Krishnan and Wicaksono, Damar Canggih and Michelfeit, Jannik and Hecht, Michael}, + title = {{Minterpy} - multivariate polynomial interpolation}, + month = dec, + year = 2024, + publisher = {RODARE}, + version = {v0.3.0}, + doi = {10.14278/rodare.3354}, + url = {http://doi.org/10.14278/rodare.3354} +} +``` ## Credits and contributors -This work was partly funded by the Center for Advanced Systems Understanding (CASUS) -that is financed by Germany’s Federal Ministry of Education and Research (BMBF) -and by the Saxony Ministry for Science, Culture and Tourism (SMWK) -with tax funds on the basis of the budget approved by the Saxony State Parliament. +This work was partly funded by the Center for Advanced Systems Understanding ([CASUS]), +an institute of the Helmholtz-Zentrum Dresden-Rossendorf ([HZDR]), +financed by Germany’s Federal Ministry of Education and Research ([BMBF]) +and by the Saxony Ministry for Science, Culture and Tourism ([SMWK]) +with tax funds on the basis of the budget approved +by the Saxony State Parliament. -### The minterpy development team +### The Minterpy development team -The core development of the `minterpy` is currently done -by a small team at the Center for Advanced Systems Understanding ([CASUS]), -namely +Minterpy is currently developed and maintained by a small team +at the Center for Advanced Systems Understanding ([CASUS]): -- Damar Wicaksono ([HZDR]/[CASUS]) (d.wicaksono@hzdr.de) -- Uwe Hernandez Acosta ([HZDR]/[CASUS]) (u.hernandez@hzdr.de) -- Janina Schreiber ([HZDR]/[CASUS]) (j.schreiber@hzdr.de) -- Sachin Krishnan Thekke Veettil ([HZDR]/[CASUS]) (s.thekke-veettil@hzdr.de) +- [Damar Wicaksono](https://orcid.org/0000-0001-8587-7730) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4528)) +- [Uwe Hernandez Acosta](https://orcid.org/0000-0002-6182-1481) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4442)) +- [Janina Schreiber](https://orcid.org/0000-0002-8692-0822) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4528)) ### Mathematical foundation -- Michael Hecht ([HZDR]/[CASUS]) (m.hecht@hzdr.de) +- [Michael Hecht](https://orcid.org/0000-0001-9214-8253) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4528)) -### Former Members and Contributions +### Former members and contributors -- Jannik Michelfeit -- Nico Hoffman ([HZDR]) -- Steve Schmerler ([HZDR]) -- Vidya Chandrashekar (TU Dresden) +- [Sachin Krishnan Thekke Veettil](https://orcid.org/0000-0003-4852-2839) +- [Jannik Kissinger](https://orcid.org/0000-0002-1819-6975) +- [Nico Hoffman](https://scholar.google.de/citations?user=8iDQeTwAAAAJ&hl=de) +- [Steve Schmerler](https://orcid.org/0000-0003-1354-0578) ([HZDR]) +- Vidya Chandrashekar ([TU Dresden](https://tu-dresden.de/)) -### Acknowledgement +### Acknowledgements -- Klaus Steiniger ([HZDR]) -- Patrick Stiller ([HZDR]) +- [Klaus Steiniger](https://orcid.org/0000-0001-8965-1149) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4353)) +- [Patrick Stiller](https://scholar.google.com/citations?user=nOtYbWMAAAAJ&hl=de) ([HZDR]) - Matthias Werner ([HZDR]) -- Krzysztof Gonciarz ([MPI-CBG],[CSBD]) -- Attila Cangi ([HZDR]/[CASUS]) -- Michael Bussmann ([HZDR]/[CASUS]) - -### Community - -This package would not be possible without many contributions done -from the community as well. -For that, we want to send big thanks to: - -- the guy who will show me how to include a list of contributors on github/gitlab +- [Krzysztof Gonciarz](https://orcid.org/0000-0001-9054-8341) ([MPI-CBG]/[CSBD]) +- [Attila Cangi](https://orcid.org/0000-0001-9162-262X) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4660)) +- [Michael Bussmann](https://orcid.org/0000-0002-8258-3881) ([HZDR]/[CASUS](https://www.casus.science/?page_id=4353)) ## License -[MIT](LICENSE) © minterpy development team - -[^1]: [arXiv:2010.10824](https://arxiv.org/abs/2010.10824) +Minterpy is released under the [MIT license](LICENSE). [mamba]: https://mamba.readthedocs.io/en/latest/ [conda]: https://docs.conda.io/ @@ -176,14 +227,11 @@ For that, we want to send big thanks to: [venv]: https://docs.python.org/3/tutorial/venv.html [virtualenv]: https://virtualenv.pypa.io/en/latest/ [pyenv-virtualenv]: https://github.com/pyenv/pyenv-virtualenv -[pre-commit]: https://pre-commit.com/ -[Jupyter]: https://jupyter.org/ -[nbstripout]: https://github.com/kynan/nbstripout -[Google style]: http://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings [virtualenv]: https://virtualenv.pypa.io/en/latest/index.html -[pytest]: https://docs.pytest.org/en/6.2.x/ [CASUS]: https://www.casus.science [HZDR]: https://www.hzdr.de +[BMBF]: https://www.bmbf.de/ +[SMWK]: https://www.smwk.sachsen.de/ [MPI-CBG]: https://www.mpi-cbg.de [CSBD]: https://www.csbdresden.de [black-badge]: https://img.shields.io/badge/code%20style-black-000000.svg diff --git a/docs/assets/images/contributors/documentation-tooling.png b/docs/assets/images/contributors/documentation-tooling.png index 3ce0042c..e353061d 100644 Binary files a/docs/assets/images/contributors/documentation-tooling.png and b/docs/assets/images/contributors/documentation-tooling.png differ diff --git a/docs/assets/images/test-function1D.png b/docs/assets/images/test-function1D.png deleted file mode 100644 index 9c055583..00000000 Binary files a/docs/assets/images/test-function1D.png and /dev/null differ diff --git a/docs/assets/images/xsinx-prod-diff.png b/docs/assets/images/xsinx-prod-diff.png new file mode 100644 index 00000000..7b31898e Binary files /dev/null and b/docs/assets/images/xsinx-prod-diff.png differ diff --git a/docs/assets/images/xsinx.png b/docs/assets/images/xsinx.png new file mode 100644 index 00000000..37ef4399 Binary files /dev/null and b/docs/assets/images/xsinx.png differ diff --git a/docs/contributors/about-us.rst b/docs/contributors/about-us.rst index a74580a2..e4ff1727 100644 --- a/docs/contributors/about-us.rst +++ b/docs/contributors/about-us.rst @@ -92,7 +92,7 @@ and code reviews.
Daniel Kotik

🚇 -
Michał Bajda

+
Michał Bajda

🎨 diff --git a/docs/contributors/contrib-docs/docs-tools.rst b/docs/contributors/contrib-docs/docs-tools.rst index 0c749713..e1309a25 100644 --- a/docs/contributors/contrib-docs/docs-tools.rst +++ b/docs/contributors/contrib-docs/docs-tools.rst @@ -23,7 +23,7 @@ Documentation generator We use the `Sphinx documentation generator`_ to build the documentation as HTML files [#]_ These HTML files can be viewed or deployed (published) as a static website -using a hosting service such as `Read the Docs`_ [#]_. +using a hosting service such as `Read the Docs`_ or `GitHub Pages`_. reStructuredText markup language ================================ @@ -69,7 +69,7 @@ Building and deploying the documentation ======================================== The figure below illustrates the different components and processes involved -in building the ``minterpy`` docs. +in building the Minterpy documentation. .. figure:: /assets/images/contributors/documentation-tooling.png :align: center @@ -91,13 +91,12 @@ while Jupyter notebooks use Markdown. .. rubric:: Footnotes .. [#] Other formats like PDF are also possible. -.. [#] `Read the Docs`_ actually runs an instance of Sphinx to build the docs - online before serving it. .. _docs-like-code framework: https://www.docslikecode.com/ .. _same repository: https://gitlab.hzdr.de/interpol/minterpy .. _Sphinx documentation generator: https://www.sphinx-doc.org/en/master/ .. _Read the Docs: https://readthedocs.org/ +.. _GitHub Pages: https://pages.github.com .. _reStructuredText (reST): https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _docstrings: https://www.python.org/dev/peps/pep-0257/ .. _PEP 287: https://www.python.org/dev/peps/pep-0287/ diff --git a/docs/getting-started/1d-polynomial-interpolation.ipynb b/docs/getting-started/1d-polynomial-interpolation.ipynb index 70f970ed..666334b1 100644 --- a/docs/getting-started/1d-polynomial-interpolation.ipynb +++ b/docs/getting-started/1d-polynomial-interpolation.ipynb @@ -32,7 +32,7 @@ "\n", "_But how to create such polynomials in the first place?_\n", "\n", - "This tutorial demonstrates how you can create such a polynomial in the most typical use case." + "This tutorial demonstrates how you can create such a polynomial from scratch in the most typical use case: interpolating a function." ] }, { @@ -129,8 +129,7 @@ "source": [ "## Motivating function\n", "\n", - "In Minterpy, the polynomials are typically (but not always) interpolating polynomials that approximate functions of interest.\n", - "In fact, this is one of the main objective of Minterpy: approximating a (multi-dimensional) function using a polynomial.\n", + "In Minterpy, polynomials are typically used to approximate functions of interest by interpolating them. This is actually one of the main goals of Minterpy: to approximate a (multidimensional) function using a polynomial.\n", "\n", "For now, however, consider the following one-dimensional function:\n", "\n", @@ -180,7 +179,9 @@ "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [ + "hide-input" + ] }, "outputs": [], "source": [ @@ -202,7 +203,7 @@ "tags": [] }, "source": [ - "With the function of interest defined, you are now ready to create a polynomial that approximates it." + "Now that you've defined your function, you're ready to create a polynomial that approximates it." ] }, { @@ -225,9 +226,9 @@ "3. **Evaluate the function of interest at the grid points**: Compute the function values at the grid points (also known as the unisolvent nodes)\n", "4. **Create a polynomial in the Lagrange basis**: Construct the interpolating polynomial in the Lagrange basis based on the evaluated points.\n", "\n", - "To perform additional operations with the interpolating polynomial, such as evaluating it a set of query points, follow this extra step:\n", + "To perform additional operations with the interpolating polynomial, such as evaluating it at a set of query points, follow this extra step:\n", "\n", - "5. **Transform the polynomial to another basis**: Change the basis of the interpolating polynomial from the Lagrange basis to another basis, preferably the Newton asis, for convenient evaluation and manipulation.\n", + "5. **Transform the polynomial to another basis**: Change the basis of the interpolating polynomial from the Lagrange basis to another basis, preferably the Newton basis, for convenient evaluation and manipulation.\n", "\n", "Let’s go through these steps one at a time." ] @@ -314,7 +315,7 @@ "source": [ "### Construct an interpolation grid\n", "\n", - "An interpolation grid is where an interpolating polynomial lives on. The bases of interpolating polynomials, such as the Lagrange or the Newton basis, are defined with respect to these grids.\n", + "An interpolation grid is where an interpolating polynomial lives on. The bases of interpolating polynomials, such as the Lagrange or the Newton basis, are built with respect to these grids.\n", "\n", "In Minterpy, interpolation grids are represented by the {py:class}`Grid <.core.grid.Grid>` class.\n", "The default constructor allows you to create an interpolation grid for a specified multi-index set (the first argument).\n", @@ -483,19 +484,19 @@ "source": [ "### Create a Lagrange polynomial\n", "\n", - "The function values at the unisolvent nodes are the same as the coefficients $c_{L, \\alpha}$ of a polynomial in the Lagrange basis:\n", + "The function values at the unisolvent nodes are equal to the coefficients of a polynomial in the Lagrange basis $c_{\\mathrm{lag}, \\alpha}$:\n", "\n", "$$\n", "Q(x) = \\sum_{\\alpha \\in A} c_{\\mathrm{lag}, \\alpha} \\Psi_{\\mathrm{lag}, \\alpha}(x),\n", "$$\n", "\n", - "where $A$ is the multi-index set and $\\Psi_{\\alpha}$'s are monomials of the Lagrange basis that satisfy:\n", + "where $A$ is the multi-index set and $\\Psi_{\\alpha}$'s are Lagrange basis polynomials, each of which satisfies:\n", "\n", "$$\n", "\\Psi_{\\mathrm{lag}, \\alpha}(p_{\\beta}) = \\delta_{\\alpha, \\beta}, p_\\beta \\in P_A,\n", "$$\n", "\n", - "where $\\delta{\\cdot, \\cdots}$ denotes the Kronecker delta.\n", + "where $\\delta{\\cdot, \\cdot}$ denotes the Kronecker delta.\n", "\n", "Polynomials in the Lagrange basis are represented by the {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` class in Minterpy.\n", "You can create an instance of {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` class with various constructors.\n", @@ -529,7 +530,7 @@ "tags": [] }, "source": [ - "Congratulations! You've just made your first polynomial in Minterpy." + "Congratulations! You've just made your first polynomial in Minterpy from scratch." ] }, { @@ -557,7 +558,7 @@ "Q(x) = \\sum_{\\alpha \\in A} c_{\\mathrm{nwt}, \\alpha} \\, \\Psi_{\\mathrm{nwt}, \\alpha}(x),\n", "$$\n", "\n", - "where $c_{\\mathrm{nwt}, \\alpha}$'s are the coefficients of the polynomial in the Newton basis and $\\Psi_{\\mathrm{nwt}, \\alpha}$ is the monomial of the Newton basis associated with multi-index element $\\alpha$:\n", + "where $c_{\\mathrm{nwt}, \\alpha}$'s are the coefficients of the polynomial in the Newton basis and $\\Psi_{\\mathrm{nwt}, \\alpha}$ is the the Newton basis polynomial associated with multi-index element $\\alpha$:\n", "\n", "$$\n", "\\Psi_{\\mathrm{nwt}, \\alpha}(x) = \\prod_{i = 0}^{\\alpha - 1} (x - p_i),\n", @@ -624,7 +625,7 @@ }, "source": [ "```{note}\n", - "There are other basis in Minterpy, but for many practical applications we recommend to use the Newton basis.\n", + "Minterpy offers other polynomial bases as well, but for most practical purposes, we recommend to use the Newton basis.\n", "```" ] }, @@ -639,9 +640,9 @@ "tags": [] }, "source": [ - "### Evaluate the polynomial on a set of query points\n", + "### Evaluate the polynomial at a set of query points\n", "\n", - "Once a polynomial in the Newton basis is obtained, you can evaluate it on a set of query points; this one of the most routine task involving polynomial approximation.\n", + "Once a polynomial in the Newton basis is obtained, you can evaluate it at a set of query points; this one of the most routine tasks involving polynomial approximation.\n", "\n", "First, create a set of equally spaced test points in $[-1, 1]$:" ] @@ -765,7 +766,7 @@ }, "source": [ "```{note}\n", - "For evaluation, an instance of polynomial expects as its input an array; as the polynomial is one dimensional the array should either be one-dimensional or two-dimensional with a single column (the column of a two-dimensional array indicates the values along each spatial dimension).\n", + "For evaluation, an instance of polynomial expects as its input an array; as the polynomial is one dimensional, the array should either be one-dimensional or two-dimensional with a single column (the column of a two-dimensional array indicates the values along each spatial dimension).\n", "```" ] }, @@ -780,7 +781,7 @@ "tags": [] }, "source": [ - "We can compare the results of the interpolating polynomial against the given function in the plot before:" + "Let's compare the results of the interpolating polynomial with the original function." ] }, { @@ -818,7 +819,7 @@ "tags": [] }, "source": [ - "Shown also in the plot are the location of unisolvent nodes and the corresponding function values." + "The plot also shows the location of the unisolvent nodes and their corresponding function values; the interpolant is indeed interpolatory." ] }, { @@ -897,7 +898,7 @@ "- the degree of polynomial interpolant\n", "\n", "All in a single function call.\n", - "This call returns a callable object that can be used with a set of query points.\n", + "The function returns a callable object that you can use to evaluate the (underlying) interpolating polynomial at a set of query points.\n", "\n", "To create an interpolant using the {py:func}`.interpolate` function with the same structure as before, use the following command:" ] @@ -959,7 +960,7 @@ "tags": [] }, "source": [ - "With this short-cut to create an interpolant where evaluation is all that is needed, let's investigate the convergence of interpolating polynomials with increasing polynomial degrees.," + "With this shortcut to create an interpolant where evaluation is all that is needed, let's investigate the convergence of interpolating polynomials with increasing polynomial degrees.," ] }, { @@ -1014,6 +1015,8 @@ "plt.plot(xx_test, yy_test);\n", "for i, n in enumerate(poly_degrees):\n", " plt.plot(xx_test, yy_poly[:, i], label=\"degree = {}\".format(n))\n", + "plt.xlabel(\"$x$\", fontsize=14)\n", + "plt.ylabel(\"$y$\", fontsize=14)\n", "plt.legend();" ] }, @@ -1063,6 +1066,8 @@ "outputs": [], "source": [ "plt.plot(poly_degrees, errors, '-x');\n", + "plt.ylabel(r\"$|| f - Q ||_\\infty$\", fontsize=14)\n", + "plt.xlabel(\"Polynomial degree ($n$)\", fontsize=14)\n", "plt.yscale(\"log\");" ] }, @@ -1097,6 +1102,8 @@ "source": [ "plt.plot(xx_test, np.abs(yy_test - yy_poly[:, -1]))\n", "plt.ylim(1e-18,1)\n", + "plt.ylabel(r\"$| f - Q |$\", fontsize=14)\n", + "plt.xlabel(\"$x$\", fontsize=14)\n", "plt.yscale(\"log\");" ] }, @@ -1115,19 +1122,34 @@ ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, + "id": "5ddc236432458232", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], "source": [ "plt.plot(xx_test, np.abs(yy_test - yy_poly[:, 0]))\n", + "plt.ylabel(r\"$| f - Q |$\", fontsize=14)\n", + "plt.xlabel(\"$x$\", fontsize=14)\n", "plt.yscale(\"log\");" - ], - "id": "5ddc236432458232" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "692e6d3992a02e39", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "## From Interpolant to polynomial\n", "\n", @@ -1143,22 +1165,23 @@ "| {py:meth}`to_newton() <.interpolation.Interpolant.to_newton>` | {py:class}`NewtonPolynomial <.polynomials.newton_polynomial.NewtonPolynomial>` |\n", "| {py:meth}`to_lagrange() <.interpolation.Interpolant.to_lagrange>` | {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` |\n", "| {py:meth}`to_canonical() <.interpolation.Interpolant.to_canonical>` | {py:class}`CanonicalPolynomial <.polynomials.canonical_polynomial.CanonicalPolynomial>` |\n", - "| {py:meth}`to_chebyshev() <.interpolation.Interpolant.to_chebyshev>` | {py:class}`CanonicalPolynomial <.polynomials.chebyshev_polynomial.ChebyshevPolynomial>` |\n", + "| {py:meth}`to_chebyshev() <.interpolation.Interpolant.to_chebyshev>` | {py:class}`ChebyshevPolynomial <.polynomials.chebyshev_polynomial.ChebyshevPolynomial>` |\n", "\n", "These bases will be the topic of {doc}`/getting-started/polynomial-bases-and-transformations`\n", "in-depth tutorial.\n", "\n", "For now to obtain the interpolating polynomial in the Newton basis, call:" - ], - "id": "692e6d3992a02e39" + ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, - "source": "fx_interp.to_newton()", - "id": "2b3192c790d330ae" + "id": "2b3192c790d330ae", + "metadata": {}, + "outputs": [], + "source": [ + "fx_interp.to_newton()" + ] }, { "cell_type": "markdown", @@ -1189,9 +1212,9 @@ "\n", "---\n", "\n", - "Minterpy, as its name implies, supports the construction of multivariate (multi-dimensional) polynomials as well. The process for constructing these polynomials follows similar steps to those described here.\n", + "Minterpy, as its name implies, supports the construction of multivariate polynomials as well. The process for constructing these polynomials follows similar steps to those described here.\n", "\n", - "In the next tutorial, you'll learn how to create multi-dimensional polynomials in Minterpy." + "In the next tutorial, you'll learn how to create multivariate polynomials to interpolate multidimensional functions using Minterpy." ] } ], @@ -1211,7 +1234,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/arithmetic-operations-with-polynomials.ipynb b/docs/getting-started/arithmetic-operations-with-polynomials.ipynb index f8139d25..4a23f228 100644 --- a/docs/getting-started/arithmetic-operations-with-polynomials.ipynb +++ b/docs/getting-started/arithmetic-operations-with-polynomials.ipynb @@ -31,21 +31,20 @@ "This tutorial will show you how to extend beyond evaluation by performing arithmetic operations with Minterpy polynomials.\n", "Specifically, you'll learn that Minterpy polynomials can be:\n", "\n", - "- added or subtracted from other polynomials\n", - "- multiplied by other polynomials or real scalar numbers\n", - "- raised to a non-negative integer power\n", + "- Added or subtracted from other polynomials\n", + "- Multiplied by other polynomials or real scalar numbers\n", + "- Raised to a power (as long as it's a non-negative integer)\n", "\n", - "These operations result in another Minterpy polynomial (in the same basis).\n", - "In other words, Minterpy polynomials are _closed_ under the following arithmetic operations:\n", + "These operations result in another Minterpy polynomial in the same basis.\n", + "In other words, Minterpy polynomials are **closed** under the following arithmetic operations:\n", "\n", - "- polynomial-polynomial multiplication\n", - "- polynomial-scalar multiplication\n", - "- polynomial-polynomial addition and subtraction\n", - "- polynomial-scalar addition and subtraction\n", - "- exponentiation by a non-negative integer\n", + "- Multiplying a polynomial by another polynomial\n", + "- Multiplying a polynomial by a scalar (a real number)\n", + "- Adding or subtracting one polynomial to/from another\n", + "- Adding or subtracting a scalar (a real number) to/from a polynomial\n", + "- Raising a polynomial to a non-negative integer power\n", "\n", - "For clarity, this in-depth tutorial uses one-dimensional polynomials as examples.\n", - "However, the principles and behaviors described are consistent across all dimensions.\n", + "To keep things simple, this tutorial uses one-dimensional polynomials as examples. However, the principles and behaviors we'll cover apply to Minterpy polynomials of any dimensions.\n", "\n", "Before you start, make sure to import the necessary packages to follow along with this guide." ] @@ -118,7 +117,9 @@ }, "tags": [] }, - "source": "Following the examples given in the {doc}`previous guide <1d-polynomial-interpolation>`, you can construct an interpolating polynomial of the function above as follows:" + "source": [ + "Following the examples given in the {doc}`previous guide <1d-polynomial-interpolation>`, you can construct an interpolating polynomial of the function above as follows:" + ] }, { "cell_type": "code", @@ -190,7 +191,7 @@ }, "source": [ "```{note}\n", - "The choice of polynomial degree above is arbitrary; in practice, you will decide whether the accuracy of an interpolating polynomial is good enough to your use case. Note also that, infinity norm is not the only measure accuracy typically used; for instance, mean-squared error is also widely used.\n", + "The choice of polynomial degree above is just an example; in practice, you will have to decide what level of accuracy is sufficient for your specific use case. Also, keep in mind that infinity norm is just one way to measure accuracy; other common metrics, like mean-squared error, are also widely used.\n", "```" ] }, @@ -345,7 +346,7 @@ "\n", "axs[1].plot(xx_plot, fun_2(xx_plot), label=\"true function ($f$)\")\n", "axs[1].plot(xx_plot, poly_2(xx_plot), label=\"polynomial ($Q$)\")\n", - "axs[1].scatter(grd_2.unisolvent_nodes[:, 0], coeffs_2)\n", + "axs[1].scatter(grd_2.unisolvent_nodes[:, 0], coeffs_2, label=\"interpolating nodes\")\n", "axs[1].set_xlabel(\"$x$\", fontsize=14);\n", "axs[1].set_ylabel(\"$f_2(x)$\", fontsize=14);\n", "axs[1].set_title(\"Exponential\", fontsize=16)\n", @@ -366,11 +367,11 @@ "tags": [] }, "source": [ - "The plots show that are no notable differences between the two true functions and their corresponding interpolating polynomials.\n", + "The plots show that there no notable differences between the two true functions and their corresponding interpolating polynomials\n", "\n", "---\n", "\n", - "With the two interpolating polynomials defined, you are now ready to do some arithmetic operations with them." + "Now that you have the two interpolating polynomials, you can start doing arithmetic operations with them." ] }, { @@ -503,7 +504,7 @@ "source": [ "Polynomials may also be added or subtracted from each other; the result is once again another polynomial.\n", "\n", - "For instance, $Q_{\\mathrm{add}} (x) = Q_1(x) + Q_2(x)$:" + "For instance, $Q_{\\mathrm{sum}} = Q_1 + Q_2$:" ] }, { @@ -519,8 +520,8 @@ }, "outputs": [], "source": [ - "poly_add = poly_1 + poly_2\n", - "poly_add" + "poly_sum = poly_1 + poly_2\n", + "poly_sum" ] }, { @@ -534,7 +535,7 @@ "tags": [] }, "source": [ - "or $Q_{\\mathrm{sub}} (x) = Q_1(x) - Q_2(x)$:" + "or $Q_{\\mathrm{diff}} = Q_1 - Q_2$:" ] }, { @@ -550,8 +551,8 @@ }, "outputs": [], "source": [ - "poly_sub = poly_1 - poly_2\n", - "poly_sub" + "poly_diff = poly_1 - poly_2\n", + "poly_diff" ] }, { @@ -588,7 +589,7 @@ "fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 4))\n", "\n", "axs[0].plot(xx_plot, poly_1(xx_plot), label=\"$Q_1$\")\n", - "axs[0].plot(xx_plot, poly_add(xx_plot), label=\"$Q_1 + Q_2$\")\n", + "axs[0].plot(xx_plot, poly_sum(xx_plot), label=\"$Q_1 + Q_2$\")\n", "axs[0].set_xlabel(\"$x$\", fontsize=14)\n", "axs[0].set_ylabel(\"$y$\", fontsize=14)\n", "axs[0].tick_params(axis='both', which='major', labelsize=12)\n", @@ -596,7 +597,7 @@ "axs[0].set_ylim([-2.75, 2.75])\n", "\n", "axs[1].plot(xx_plot, poly_1(xx_plot), label=\"$Q_1$\")\n", - "axs[1].plot(xx_plot, poly_sub(xx_plot), label=\"$Q_1 - Q_2$\")\n", + "axs[1].plot(xx_plot, poly_diff(xx_plot), label=\"$Q_1 - Q_2$\")\n", "axs[1].set_xlabel(\"$x$\", fontsize=14);\n", "axs[1].tick_params(axis='both', which='major', labelsize=12)\n", "axs[1].legend(fontsize=14, loc=\"lower right\")\n", @@ -620,7 +621,7 @@ "\n", "Minterpy polynomials may also be multiplied by a real scalar number; the operation returns another polynomial.\n", "\n", - "Consider $5 \\times Q_2(x)$:" + "Consider $5 \\times Q_2$:" ] }, { @@ -692,7 +693,7 @@ "source": [ "Furthermore, a multiplication between Minterpy polynomials is also a valid operation that returns a polynomial.\n", "\n", - "For instance $Q_1 \\times Q_2$:" + "For instance, $Q_{\\mathrm{prod}} = Q_1 \\times Q_2$:" ] }, { @@ -708,8 +709,8 @@ }, "outputs": [], "source": [ - "poly_mul = poly_1 * poly_2\n", - "poly_mul" + "poly_prod = poly_1 * poly_2\n", + "poly_prod" ] }, { @@ -758,7 +759,7 @@ "axs[1].legend(fontsize=14, loc=\"upper right\")\n", "axs[1].set_ylim([-2.0, 2.25])\n", "\n", - "axs[2].plot(xx_plot, poly_mul(xx_plot), label=\"$Q_1 \\\\times Q_2$\")\n", + "axs[2].plot(xx_plot, poly_prod(xx_plot), label=\"$Q_1 \\\\times Q_2$\")\n", "axs[2].set_xlabel(\"$x$\", fontsize=14)\n", "axs[2].tick_params(axis='both', which='major', labelsize=12)\n", "axs[2].legend(fontsize=14);\n", @@ -799,7 +800,7 @@ "\n", "Minterpy polynomials may be divided by a real scalar number; this operation returns another polynomial.\n", "\n", - "For instance $Q_1(x) / 4.0$:" + "For instance, $Q_1 / 4.0$:" ] }, { @@ -872,7 +873,7 @@ "Minterpy, however, does **not support** polynomial-polynomial division (rational function). Minterpy cannot evaluate the resulting function of the expression:\n", "\n", "$$\n", - "Q_3(x) = \\frac{Q_1(x)}{Q_2(x)}\n", + "Q_3 = \\frac{Q_1}{Q_2}\n", "$$\n", "\n", "and return the resulting rational function." @@ -911,7 +912,7 @@ "\n", "Finally, Minterpy polynomials may also be exponentiated by a **non-negative integer**. As all the other arithmetic operations above, polynomial exponentiation returns another polynomial.\n", "\n", - "For instance $Q_1^2(x)$:" + "For instance, $Q_1^2$:" ] }, { @@ -967,9 +968,9 @@ "tags": [] }, "source": [ - "Polynomial exponentiation by a non-negative integer is a syntactic sugar for multiple polynomial self multiplications.\n", + "Raising a polynomial to a non-negative integer power is equivalent to performing multiple-self multiplications of the polynomial.\n", "\n", - "For instance, $Q_2^2(x) = Q_2(x) \\times Q_2(x)$:" + "For instance, $Q_2^2 = Q_2 \\times Q_2$:" ] }, { @@ -999,7 +1000,7 @@ "tags": [] }, "source": [ - "or $Q_2^3(x) = Q_2(x) \\times Q_2(x) \\times Q_2(x)$:" + "or $Q_2^3 = Q_2 \\times Q_2 \\times Q_2$:" ] }, { @@ -1029,7 +1030,7 @@ "tags": [] }, "source": [ - "Finally, polynomial exponentiation by $0$ returns a constant polynomial with the value of $1.0$." + "Finally, raising a polynomial to the power of $0$ results in a constant polynomial with a value of $1.0$." ] }, { @@ -1076,8 +1077,8 @@ "axs[0].legend(fontsize=14, loc=\"lower right\")\n", "axs[0].set_ylim([-1.5, 2.25])\n", "\n", - "axs[1].plot(xx_plot, poly_2(xx_plot), label=\"$Q_1$\")\n", - "axs[1].plot(xx_plot, poly_2_exp_0(xx_plot), label=\"$Q_1^0$\")\n", + "axs[1].plot(xx_plot, poly_2(xx_plot), label=\"$Q_2$\")\n", + "axs[1].plot(xx_plot, poly_2_exp_0(xx_plot), label=\"$Q_2^0$\")\n", "axs[1].set_xlabel(\"$x$\", fontsize=14);\n", "axs[1].tick_params(axis='both', which='major', labelsize=12)\n", "axs[1].legend(fontsize=14, loc=\"lower right\")\n", @@ -1098,7 +1099,7 @@ }, "source": [ "```{warning}\n", - "Minterpy polynomials cannot be exponentiated by another polynomial, a negative number, or a non-integer. Attempting to carry out these operations will raise an exception.\n", + "Note that Minterpy polynomials do not support exponentiation by another polynomial, a negative number, or a non-integer value. If you attempt to perform such an operation, an exception will be raised.\n", "```" ] }, @@ -1116,7 +1117,7 @@ "## Summary\n", "\n", "In this in-depth tutorial, you've learned about the basic arithmetic operations involving Minterpy polynomials.\n", - "Minterpy polynomials are closed under the following arithmetic operations, meaning that performing these operations results in another Minterpy polynomial:\n", + "Minterpy polynomials are **closed** under the following arithmetic operations, meaning that the result of the performing these operations is always another Minterpy polynomial:\n", "\n", "- Polynomial-scalar addition and subtraction\n", "- Polynomial-polynomial addition and subtraction\n", @@ -1127,10 +1128,10 @@ "\n", "Throughout the tutorial, one-dimensional polynomials were used for illustration, but the principles apply similarly to Minterpy polynomials of higher dimensions.\n", "\n", - "Please note that Minterpy currently does not support:\n", + "Please note that Minterpy currently **does not support**:\n", "\n", "- Polynomial-polynomial division (i.e., forming _rational functions_)\n", - "- Polynomial exponentiation by a real scalar (including negative integers and non-integer numbers)\n", + "- Polynomial exponentiation by another polynomial or by a real scalar (including negative integers and non-integer numbers)\n", "\n", "---\n", "\n", @@ -1154,7 +1155,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/calculus-operations-with-polynomials.ipynb b/docs/getting-started/calculus-operations-with-polynomials.ipynb index 3df73ab6..1546b1e2 100644 --- a/docs/getting-started/calculus-operations-with-polynomials.ipynb +++ b/docs/getting-started/calculus-operations-with-polynomials.ipynb @@ -365,9 +365,14 @@ "tags": [] }, "source": [ - "To specify custom bounds for definite integration in Minterpy, you can pass a list of lists where each inner list contains the lower and upper bounds for each dimension.\n", - "This allows you to compute integrals over particular regions of interest.\n", - "\n", + "To define custom bounds for definite integration in Minterpy, pass a list of lists, where each inner list specifies the lower and upper bounds for a particular dimension, in the order dimension (i.e., the first inner list corresponds to the first dimension, the second inner list corresponds to the second dimension, and so on). This enables you to compute integrals over specific regions of interest." + ] + }, + { + "cell_type": "markdown", + "id": "bd106b21-bf11-4e4f-950e-311c736d0da9", + "metadata": {}, + "source": [ "For instance, to compute:\n", "\n", "$$\n", @@ -465,7 +470,7 @@ }, "source": [ "```{note}\n", - "The spatial dimension specification starts with $0$, i.e., $0$ is index for the first spatial dimension.\n", + "The spatial dimension specification starts with $0$, i.e., $0$ is the index for the first spatial dimension.\n", "```" ] }, @@ -606,7 +611,7 @@ "tags": [] }, "source": [ - "The method {py:meth}`diff() <.polynomials.newton_polynomial.NewtonPolynomial.diff>` allows you to specify the order of derivative for each spatial dimension simultaneously by passing a list or NumPy array.\n", + "The {py:meth}`diff() <.polynomials.newton_polynomial.NewtonPolynomial.diff>` method enables you to compute the derivatives of varying oders for each spatial dimension simultaneously. To do this, pass a list or a NumPy array specifying the desired order of derivative for each dimension.\n", "\n", "See the following table for examples.\n", "\n", @@ -762,18 +767,17 @@ "\n", "These operations were demonstrated using a two-dimensional polynomial, but they apply similarly to polynomials of higher dimensions.\n", "\n", - "\n", "---\n", "\n", - "So far, this series of in-depth tutorials have covered:\n", + "Throughout this series of in-depth tutorials, we've explored the following topics:\n", "\n", - "- contructing Minterpy polynomials, from one-dimensional to multi-dimensional cases\n", - "- performing basic arithmetic operations with the polynomials such as addition, subtraction, and multiplication.\n", - "- performing basic calculus operations with the polynomials such as differentiation and definite integration\n", + "- Constructing Minterpy polynomials, from simple {doc}`one-dimensional <1d-polynomial-interpolation>` cases to more complex {doc}`multivariate ` ones;\n", + "- Performing basic {doc}`arithmetic operations ` with Minterpy polynomials, including addition, subtraction, and multiplication;\n", + "- Applying basic calculus operations to Minterpy polynomials, including differentiation and definite integration (_this tutorial_).\n", "\n", - "In all the examples, you began with a polynomial in the Lagrange basis and then transformed it into a polynomial in the Newton basis.\n", + "In the examples we've explored so far, we've started with a polynomial in the Lagrange basis and then converted it to a polynomial in the Newton basis. However, Minterpy offers more flexibility than that.\n", "\n", - "In fact, polynomials in Minterpy can be represented in different bases (beyond just Lagrange or Newton). The tutorial will provide an overview of the available bases and the transformations between them." + "Polynomials can be represented in a variety of bases, extending beyond just Lagrange and Newton. In the next tutorial, we'll delve into different bases available in Minterpy and discuss how to transform polynomials between the." ] } ], @@ -793,7 +797,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/functions-approximation.ipynb b/docs/getting-started/function-approximations.ipynb similarity index 82% rename from docs/getting-started/functions-approximation.ipynb rename to docs/getting-started/function-approximations.ipynb index 8b6a04cf..aee8dd9c 100644 --- a/docs/getting-started/functions-approximation.ipynb +++ b/docs/getting-started/function-approximations.ipynb @@ -27,8 +27,7 @@ "source": [ "Welcome to the Quickstart Guide to Minterpy!\n", "\n", - "If you're here, you likely want to create an interpolant that approximates a function, possibly in multiple dimensions.\n", - "This guide will quickly show you how to do that using Minterpy." + "If you're reading this, chances are you want to create an interpolant that approximates a function, possibly in multiple dimensions. This guide provides a quick walkthrough on how to achieve this using Minterpy." ] }, { @@ -214,19 +213,25 @@ "source": [ "### One-dimensional interpolant\n", "\n", - "To create an interpolant in Minterpy, you can use the function {py:func}`.interpolate` which takes the following argument (in order):\n", + "To create an interpolant in Minterpy, use the {py:func}`.interpolate` function which accepts the following arguments in order:\n", "\n", - "- the function to interpolate (a callable that takes an array of input values and returns an array of output values of the same length)\n", - "- the spatial dimension of the function\n", - "- the degree of the polynomial interpolant\n", + "1. The function to interpolate (a callable that takes an array of input values and returns an array of output values of the same length)\n", + "2. The spatial dimension of the function\n", + "3. The degree of the polynomial interpolant\n", "\n", "The lambda function you've defined above already satisfies the first requirement: as a callable, it takes an array of input values and returns an array of output values.\n", "\n", - "The spatial dimension of the function is $1$; since Minterpy cannot infer the dimensionality of your function, you need to specify this.\n", + "The spatial dimension of the function, which represents the number of input variables it accepts, is $1$. Since Minterpy cannot automatically infer the dimensionality of your function, you must specify this value explicitly.\n", "\n", - "Finally, you need to choose the degree of the polynomial interpolant. Since Minterpy interpolants are based on polynomials, specifying the degree in advance is necessary. As a best practice, you should later verify whether the interpolant achieves sufficient accuracy.\n", - "\n", - "Let's say that the chosen polynomial degree is $8$:" + "Finally, you need to specify the degree of the polynomial interpolant. Because Minterpy interpolants are based on polynomials, it is necessary to choose the polynomial degree in advance. As a best practice, it is recommended to verify the accuracy of the interpolant after creation to ensure it meets your requirements." + ] + }, + { + "cell_type": "markdown", + "id": "3e3e0d90-e220-452c-8c54-e6930b8f6d43", + "metadata": {}, + "source": [ + "For instance, let's say you choose a polynomial degree of $8$:" ] }, { @@ -339,7 +344,7 @@ "tags": [] }, "source": [ - "It seems that the interpolant still a bit off and does not approximate the function nicely." + "However, the interpolant doesn't quite match the function as closely as we'd like." ] }, { @@ -407,7 +412,7 @@ "tags": [] }, "source": [ - "Whether the given norm is sufficiently low depends on your application. But we might agree, for now, that the number above is hardly a numerical convergence." + "Whether the given norm is low enough depends on what you're using the interpolant for. But for now, let's agree that the number above isn't exactly a numerical convergence." ] }, { @@ -489,8 +494,15 @@ "tags": [] }, "source": [ - "Visually, there is no notable difference between the interpolant of degree $32$ and the original function.\n", - "And indeed the infinity norm is now:" + "Looking at the graph, it's hard to see any difference between the interpolant of degree $32$ and the original function." + ] + }, + { + "cell_type": "markdown", + "id": "925c1c2f-901e-4661-8bd5-9644bec6bf05", + "metadata": {}, + "source": [ + "Looking at the infinity norm:" ] }, { @@ -522,7 +534,7 @@ "tags": [] }, "source": [ - "which is close to numerical convergence." + "which is now closer to numerical convergence." ] }, { @@ -538,7 +550,7 @@ "source": [ "## Two-dimensional function\n", "\n", - "Consider now two-dimensional function:\n", + "Consider now a two-dimensional function:\n", "\n", "$$\n", "f(x_1, x_2) = \\sin{\\pi (1.5 x_1 + 2.5 x_2)}, x_1, x_2 \\in [-1, 1].\n", @@ -662,14 +674,20 @@ "source": [ "### Two-dimension interpolant\n", "\n", - "The function {py:func}`.interpolate` also accepts two-dimensional functions for interpolation. Here are a few things to note:\n", - "\n", - "- The function must accept a two-dimensional array as input, where each row corresponds to input values in multiple dimensions, and each column corresponds to input values for each spatial dimension. In this case, the input array is expected to have $2$ columns (for spatial dimension $2$). Furthermore, the function must return an array with the same length as the length of the input (i.e., the number of rows).\n", - "- As previously mentioned, you need to specify that the function to interpolate has a spatial dimension of $2$.\n", + "The function {py:func}`.interpolate` can also handle two-dimensional functions. Here are a few things to note:\n", "\n", - "Additionally, when the spatial dimension is more than $1$, there is one more argument you can specify: the $l_p$-degree. This degree is related to the specification of the underlying multi-index set of exponents. Some choices of $l_p$-degree may approximate a given function better than others. See the {ref}`relevant section ` for details. This argument is optional, with the default value set to $2.0$.\n", + "- Your function should take a two-dimensional (2D) array as input, where each row represents a point in space and each column corresponds to a spatial dimension. For functions defined in 2D space, this means the input array must have exactly two columns. The function should return an array with the same number of rows as the input.\n", + "- As mentioned earlier, make sure to specify that your function has a spatial dimension of $2$ when calling {py:func}`.interpolate`. \n", "\n", - "To create a two-dimensional interpolant with a polynomial degree of $32$, you would proceed as follows:" + "One more thing to note: when you're working with functions of more than one spatial dimension, you can also specify the $l_p$-degree argument. This controls the underlying multi-index set of exponents used in the interpolation. Different $l_p$-degree values can affect how well the interpolant approximates the original function. Checkout the {ref}`relevant section ` for details. If you don't specify an $l_p$-degree, it defaults to $2.0$." + ] + }, + { + "cell_type": "markdown", + "id": "36208d48-84e6-40fc-8e89-c96834401593", + "metadata": {}, + "source": [ + "To create a two-dimensional interpolant with a polynomial degree of $32$, use the following command:" ] }, { @@ -774,8 +792,14 @@ "source": [ "### Assessing 2D interpolant accuracy\n", "\n", - "It is hard by looking at the plot above to conclude that interpolant is accurate enough; the interpolant does capture the overall shape of the original function, though.\n", - "\n", + "Just by looking at the plot, it's though to say for sure if the interpolant is accurate enough. But it does seem to capture the overall shape of the function pretty well." + ] + }, + { + "cell_type": "markdown", + "id": "2e3edf8d-1af2-4693-a47d-fb5af8ff144f", + "metadata": {}, + "source": [ "As explained previously, you can use the infinity norm to quantify the accuracy of the interpolant.\n", "To estimate it using, say, $100'000$ random points in $[-1, 1]^2$:" ] @@ -825,7 +849,7 @@ "source": [ "## Four-dimensional function\n", "\n", - "You've seen how to interpolate a one-dimensional and a two-dimensional function. How about functions in higher dimension?\n", + "So far, you've seen how to interpolate 1D and 2D functions. But what about functions with even more dimensions?\n", "\n", "Consider now the $m$-dimensional Runge function:\n", "\n", @@ -883,13 +907,19 @@ "source": [ "### Four-dimension interpolant\n", "\n", - "The choice of the function above is to demonstrate that the function {py:func}`.interpolate` works the same way as it does for one- and two-dimensional functions.\n", - "\n", - "You just need to ensure that the function to interpolate conforms to Minterpy's requirements: it should be a callable that accepts a two-dimensional array where each row corresponds to a point in a multi-dimensional space, and each column corresponds to values in the spatial dimension.\n", + "The $m$-dimensional Runge function defined above is chosen to show that {py:func}`.interpolate` works the same way for higher-dimensional functions as it does for 1D and 2D ones.\n", "\n", - "Similar to the two-dimensional case, you have the option to adjust the $l_p$-degree of the underlying multi-index set. Again, this is optional.\n", + "Just make sure your function meets Minterpy's requirements: it should be a callable that takes a 2D array as input, where each row represents a point in multidimensional space and each column corresponds to a spatial dimension (so in this case, four columns).\n", "\n", - "To create a four-dimensional interpolant with a polynomial degree of $16$, you would proceed as follows:" + "Just like with 2D functions, you can also tweak the $l_p$-degree of the underlying multi-index set for higher-dimensional functions ($m > 1$). This is optional, but can affect the accuracy of the interpolant." + ] + }, + { + "cell_type": "markdown", + "id": "a0691001-8113-4c68-b551-eef683b89236", + "metadata": {}, + "source": [ + "To create a 4D interpolant with a polynomial degree of $16$, use the following command:" ] }, { @@ -921,8 +951,8 @@ "source": [ "### Assessing 4D interpolant accuracy\n", "\n", - "Just, you can use the infinity norm to quantify the accuracy of the interpolant.\n", - "To estimate it using, say, $10'000$ random points in $[-1, 1]^4$:" + "As before, you can use the infinity norm to gauge the accuracy of the interpolant. To estimate it using \n", + "$10'000$ random points in $[-1, 1]^4$, you can use the following code:" ] }, { @@ -995,7 +1025,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/index.rst b/docs/getting-started/index.rst index 6c5a2b8d..cff39d2c 100644 --- a/docs/getting-started/index.rst +++ b/docs/getting-started/index.rst @@ -26,7 +26,7 @@ Installation .. code-block:: bash - git clone -b dev https://github.com/casus/minterpy + git clone -b dev https://github.com/minterpy-project/minterpy After moving inside the cloned directory, the package can be installed from source with ``pip``: @@ -35,9 +35,9 @@ Installation pip install [-e] . -A best practice is to create a virtual environment so as not to install -external package to the your base Python environment. -You can do this with the help of, among others: +As a best practice, it is recommended to create a virtual environment +to avoid installing external packages directly into your base Python environment. +You can accomplish this using tools such as: - `venv`_ - `virtualenv`_ @@ -50,12 +50,12 @@ What's next? If you're brand new to Minterpy and simply want to approximate a function using polynomial interpolations, start with: -:doc:`functions-approximation` +:doc:`function-approximations` -While approximating functions using polynomials is a main feature of Minterpy, -it also offers multi-dimensional polynomials in Python. -These polynomials have a consistent interface that allows for advanced -manipulation such arithmetic and calculus operations. +While function approximation using polynomials is a key feature of Minterpy, +the package also provides a powerful implementation of multivariate polynomials in Python. +These polynomials have a consistent interface that makes it easy +to perform advanced manipulations like arithmetic and calculus operations. To learn more about these features of Minterpy, follow the series of tutorials below. We recommend that you go through these tutorials in sequence. @@ -65,9 +65,10 @@ below. We recommend that you go through these tutorials in sequence. * - If you want to... - Go to... - * - understand Minterpy polynomials through approximating a 1D function + * - understand Minterpy polynomials by approximating a 1D function - :doc:`1d-polynomial-interpolation` - * - learn how to approximate mD function with polynomial interpolation + * - learn how to approximate multidimensional function using + polynomial interpolation - :doc:`md-polynomial-interpolation` * - know more about the supported *arithmetic operations* with Minterpy polynomials @@ -88,7 +89,7 @@ a particular task, be sure to check out the :doc:`/how-to/index`! :maxdepth: 1 :hidden: - Functions approximation + Function Approximations 1D Polynomial Interpolation <1d-polynomial-interpolation> mD Polynomial Interpolation Arithmetic with Polynomials diff --git a/docs/getting-started/md-polynomial-interpolation.ipynb b/docs/getting-started/md-polynomial-interpolation.ipynb index 9c76f28f..6e5ac3a0 100644 --- a/docs/getting-started/md-polynomial-interpolation.ipynb +++ b/docs/getting-started/md-polynomial-interpolation.ipynb @@ -10,7 +10,9 @@ }, "tags": [] }, - "source": "# Multidimensional Polynomial Interpolation" + "source": [ + "# Multivariate Polynomial Interpolation" + ] }, { "cell_type": "markdown", @@ -25,7 +27,7 @@ "source": [ "In the {doc}`previous guide `,\n", "you learned the basics of polynomial interpolation in Minterpy for approximating one-dimensional functions.\n", - "As the name \"Minterpy\" suggests, the package also supports constructing multivariate (multidimensional) function.\n", + "As the name \"Minterpy\" suggests, the package also supports constructing multivariate polynomials to approximate multidimensional functions.\n", "\n", "In this in-depth tutorial, you will learn how to create an interpolating polynomial that approximates a two-dimensional function.\n", "We use a two-dimensional example for ease of visualization, but the main steps you'll learn are applicable to polynomials of higher dimensions as well." @@ -246,7 +248,7 @@ "4. Create a polynomial in the Lagrange basis\n", "5. Transformation from the Lagrange basis to another basis, preferrably the Newton basis, for further manipulation.\n", "\n", - "As before, we will go through these steps one at a time, highlighting any differences that arise compared to the one dimensional case." + "As before, we will go through these steps one at a time, highlighting any differences that arise compared to the one-dimensional case." ] }, { @@ -264,7 +266,7 @@ "\n", "As demonstrated in the previous tutorial, multi-index sets in Minterpy are represented by the {py:class}`MultiIndexSet <.core.multi_index.MultiIndexSet>` class.\n", "You can use the class method {py:meth}`from_degree() <.MultiIndexSet.from_degree>` to create a complete multi-index set for a given spatial dimension (first argument), polynomial degree and polynomial degree (second argument).\n", - "For multidimensional polynomials, you also need to specify the $l_p$-degree ($> 0.0$) of the multi-index set (third argument).\n", + "For multivariate polynomials, you also need to specify the $l_p$-degree ($> 0.0$) of the multi-index set (third argument).\n", "\n", "A complete multi-index set with spatial dimension $m$, polynomial degree $n$, and $l_p$-degree $p$ denoted by $A_{m, n, p}$ includes all multi-indices $\\boldsymbol{\\alpha}$ that satisfy the condition $\\lVert \\boldsymbol{\\alpha} \\rVert_p \\leq n$, specifically\n", "\n", @@ -305,7 +307,9 @@ }, "tags": [] }, - "source": "The set contains the exponents of a multidimensional polynomial. Each column corresponds to the exponents per spatial dimension, while each row indicates the multi-index elements." + "source": [ + "The set contains the exponents of a multidimensional polynomial. Each column corresponds to the exponents per spatial dimension, while each row indicates the multi-index elements." + ] }, { "cell_type": "markdown", @@ -348,7 +352,7 @@ "tags": [] }, "source": [ - "Several common choices for $l_p$-degree are $1.0$ (_total-degree set_), $2.0$ (_euclidian-degree set_), and $\\infty$ (_tensorial set_).\n", + "Several common choices for $l_p$-degree are $1.0$ (_total-degree set_), $2.0$ (_Euclidean-degree set_), and $\\infty$ (_maximum-degree set_).\n", "The illustration below shows the difference between these three different choices of $l_p$-degree (for the same spatial dimension and polynomial degree) in relation to the exponents as multi-indices." ] }, @@ -410,7 +414,7 @@ "\n", "An interpolating polynomial, one-dimensional or otherwise, lives on an interpolation grid.\n", "\n", - "To construct an interpolation grid, pass the previously defined multi-index set to the default constructor of the {py:class}`Grid <.cor.grid.Grid>` class:" + "To construct an interpolation grid, pass the previously defined multi-index set to the default constructor of the {py:class}`Grid <.core.grid.Grid>` class:" ] }, { @@ -585,19 +589,19 @@ "source": [ "### Create a polynomial in the Lagrange basis\n", "\n", - "The function values at the unisolvent nodes are the same as the coefficients $c_{\\boldsymbol{\\alpha}}$ of a polynomial in the Lagrange basis:\n", + "The function values at the unisolvent nodes are equal to the coefficients of a polynomial in the Lagrange basis $c_{\\mathrm{lag}, \\boldsymbol{\\alpha}}$:\n", "\n", "$$\n", "Q(\\boldsymbol{x}) = \\sum_{\\boldsymbol{\\alpha} \\in A_{m, n, p}} c_{\\mathrm{lag}, \\boldsymbol{\\alpha}} \\Psi_{\\mathrm{lag}, \\boldsymbol{\\alpha}}(\\boldsymbol{x}),\n", "$$\n", "\n", - "where $A_{m, n, p}$ is the complete multi-index set and $\\Psi_{\\mathrm{lag}, \\boldsymbol{\\alpha}}$'s are the monomials of the Lagrange basis that satisfy:\n", + "where $A_{m, n, p}$ is the complete multi-index set and $\\Psi_{\\mathrm{lag}, \\boldsymbol{\\alpha}}$'s are the Lagrange basis polynomials, each of which satisfies:\n", "\n", "$$\n", "L_{\\boldsymbol{\\alpha}}(p_{\\boldsymbol{\\beta}}) = \\delta_{\\boldsymbol{\\alpha}, \\boldsymbol{\\beta}}, p_{\\boldsymbol{\\beta}} \\in P_{A_{m, n, p}},\n", "$$\n", "\n", - "where $\\delta{\\cdot, \\cdots}$ denotes the Kronecker delta.\n", + "where $\\delta{\\cdot, \\cdot}$ denotes the Kronecker delta.\n", "\n", "To create a polynomial in the Lagrange basis from the given grid and coefficients, use the {py:meth}`from_grid() <.polynomials.lagrange_polynomial.LagrangePolynomial.from_grid>` class method of {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` class:" ] @@ -637,13 +641,23 @@ "Q(\\boldsymbol{x}) = \\sum_{\\boldsymbol{\\alpha} \\in A_{m, n, p}} c_{\\mathrm{nwt}, \\boldsymbol{\\alpha}} \\, \\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}(\\boldsymbol{x}),\n", "$$\n", "\n", - "where $c_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}$'s are the coefficients of the polynomial in the multidimensional Newton basis and $\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}$'s are the monomials of the Newton basis. The monomial associated with multi-index element $\\boldsymbol{\\alpha}$ is defined as follows:\n", + "where $c_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}$'s are the coefficients of the polynomial in the multidimensional Newton basis and $\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}$'s are the Newton basis polynomials. The basis polynomial associated with multi-index element $\\boldsymbol{\\alpha}$ is defined as follows:\n", "\n", "$$\n", - "\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}(\\boldsymbol{x}) = \\prod_{j = 1}^m \\prod_{i = 0}^{\\alpha - 1} (x_j - p_{i, j}),\n", + "\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}}(\\boldsymbol{x}) = \\prod_{j = 1}^m \\prod_{i = 0}^{\\alpha_j - 1} (x_j - p_{i, j}),\n", "$$\n", "\n", - "where $p_{i, j}$'s are the interpolation points along dimension $j$ (i.e., the so-called {ref}`generating points / nodes ` which in multiple dimensions are not the same as the unisolvent nodes)." + "where $p_{i, j}$'s are the interpolation points along dimension $j$ (i.e., the so-called **generating points**)." + ] + }, + { + "cell_type": "markdown", + "id": "77cec92b-104e-46b1-9157-00fff5bfead2", + "metadata": {}, + "source": [ + "```{note}\n", + "In multiple dimensions (i.e., $m > 1$), the {ref}`generating points / nodes ` are not the same same as the unisolvent nodes.\n", + "```" ] }, { @@ -690,7 +704,7 @@ "```{note}\n", "In the above statement, the first part of the call, `mp.LagrangeToNewton(lag_poly)`, creates a transformation instance that converts the given polynomial from the Lagrange basis to the Newton basis.\n", "\n", - "The second call, which is made without any arguments, performs the transformation and returns the actual Newton polynomial instance.\n", + "The second call, which is made without any arguments, performs the transformation and returns the actual {py:class}`NewtonPolynomial <.polynomials.newton_polynomial.NewtonPolynomial>` instance.\n", "```" ] }, @@ -705,7 +719,7 @@ "tags": [] }, "source": [ - "### Evaluate the polynomial\n", + "### Evaluate the polynomial at a set of query points\n", "\n", "Create a set of random query points in $[-1, 1]^2$:" ] @@ -799,7 +813,7 @@ "tags": [] }, "source": [ - "Note that the input array must have two columns because the polynomial is two dimension." + "Keep in mind that the input array should have two columns, as the polynomial is two-dimensional." ] }, { @@ -813,7 +827,7 @@ "tags": [] }, "source": [ - "As expected, evaluating the polynomial on $1'000$ query points returns an array $1'000$ points:" + "As expected, evaluating the polynomial at $1'000$ query points returns an array with $1'000$ values:" ] }, { @@ -843,7 +857,7 @@ "tags": [] }, "source": [ - "We can compare the surface plot of the original function and the interpolating polynomial (with the interpolating points):" + "We can compare the surface plot of the original function with that of the interpolating polynomial, which also includes the interpolating nodes:" ] }, { @@ -922,16 +936,16 @@ "source": [ "### Assess the accuracy of the polynomial\n", "\n", - "As shown in the plot above, the chosen polynomial degree is not accurate enough to approximate the true function.\n", + "As you can see in the plot above, the chosen polynomial degree isn't sufficient to accurately approximate the original function. The interpolating polynomial misses some of the key features of the original function.\n", "\n", "The infinity norm provides a measure of the greatest error of the interpolant over the whole domain.\n", "The norm is defined as:\n", "\n", "$$\n", - "\\lVert f - Q \\rVert_\\infty = \\sup_{-1 \\leq x \\leq 1} \\lvert f(x) - Q(x) \\rvert\n", + "\\lVert f - Q \\rVert_\\infty = \\sup_{\\boldsymbol{x} \\in [-1, 1]^2} \\lvert f(\\boldsymbol{x}) - Q(\\boldsymbol{x}) \\rvert\n", "$$\n", "\n", - "The infinity norm of $Q$ can be approximated using the $1'000$ testing points created above:" + "The infinity norm of $Q$ can be approximated using the $1'000$ test points created above:" ] }, { @@ -961,7 +975,7 @@ "tags": [] }, "source": [ - "The number indicates that the interpolating polynomial with the choice of $n$ and $p$ is not yet converged." + "This number suggests that the interpolating polynomial hasn't converged yet with the current choices of $n$ and $p$." ] }, { @@ -977,9 +991,8 @@ "source": [ "## Assess the empirical convergence of interpolating polynomials\n", "\n", - "To assess the convergence of interpolating polynomials, you can once again resort to the high-level function `interpolate()` as a shortcut to the steps taken above.\n", - "Let's investigate the convergence of interpolating polynomials with increasing polynomial degrees and three different choices of $l_p$-degrees:\n", - "\n" + "To assess the convergence of interpolating polynomials, you can once again resort to the high-level function {py:func}`.interpolate` as a shortcut to the steps taken above.\n", + "Let's investigate the convergence of interpolating polynomials with increasing polynomial degrees and three different choices of $l_p$-degrees:" ] }, { @@ -1089,7 +1102,7 @@ "tags": [] }, "source": [ - "The surface plots of the original function and the interpolating polynomial for $n = 100$ and $p = 2.0$ (which according to the plots above is numerically converged) are shown below." + "Below are the surface plots of the original function and the interpolating polynomial with $n = 100$ and $p = 2.0$, which appears to be numerically converged based on the above plots." ] }, { @@ -1157,8 +1170,9 @@ ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "532a5402311dab2d", + "metadata": {}, "source": [ "## From Interpolant to polynomial\n", "\n", @@ -1175,22 +1189,23 @@ "| {py:meth}`to_newton() <.interpolation.Interpolant.to_newton>` | {py:class}`NewtonPolynomial <.polynomials.newton_polynomial.NewtonPolynomial>` |\n", "| {py:meth}`to_lagrange() <.interpolation.Interpolant.to_lagrange>` | {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` |\n", "| {py:meth}`to_canonical() <.interpolation.Interpolant.to_canonical>` | {py:class}`CanonicalPolynomial <.polynomials.canonical_polynomial.CanonicalPolynomial>` |\n", - "| {py:meth}`to_chebyshev() <.interpolation.Interpolant.to_chebyshev>` | {py:class}`CanonicalPolynomial <.polynomials.chebyshev_polynomial.ChebyshevPolynomial>` |\n", + "| {py:meth}`to_chebyshev() <.interpolation.Interpolant.to_chebyshev>` | {py:class}`ChebyshevPolynomial <.polynomials.chebyshev_polynomial.ChebyshevPolynomial>` |\n", "\n", "These bases will be the topic of {doc}`/getting-started/polynomial-bases-and-transformations`\n", "in-depth tutorial.\n", "\n", - "For now to obtain the interpolating polynomial in the Newton basis, call:" - ], - "id": "532a5402311dab2d" + "To get the interpolating polynomial in the Newton basis, call:" + ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, - "source": "fx_interp.to_newton()", - "id": "2387441ac00b1b8c" + "id": "2387441ac00b1b8c", + "metadata": {}, + "outputs": [], + "source": [ + "fx_interp.to_newton()" + ] }, { "cell_type": "markdown", @@ -1205,7 +1220,7 @@ "source": [ "## Summary\n", "\n", - "In this tutorial, you learned how to create a two-dimensional interpolating polynomial from scratch to approximate a given function then evaluate it at a set of query points in Minterpy.\n", + "In this tutorial, you learned how to create a two-dimensional (2D) interpolating polynomial from scratch to approximate a given function then evaluate it at a set of query points in Minterpy.\n", "\n", "The steps are:\n", "\n", @@ -1215,12 +1230,11 @@ "4. Construct an interpolating polynomial in the Lagrange basis\n", "5. Transform the polynomial into the equivalent Newton basis\n", "\n", - "As you observed, these steps mirror those from the {doc}`1d-polynomial-interpolation` tutorial.\n", - "A few key points for multidimensional polynomials are:\n", + "As you've seen, these steps are similar to the ones in the {doc}`1d-polynomial-interpolation` tutorial. Here are some key things to keep in mind when working with multivariate polynomials:\n", "\n", - "- you must specify the $l_p$-degree to fully define the multi-index set.\n", - "- the function of interest should accept a two-dimensional array, where each row corresponds to a multidimensional point and each column correspondds to the value per dimension.\n", - "- when evaluating an interpolating polynomial, the input should also match this two-dimensional array structure.\n", + "- You need to specify the $l_p$-degree $p$ to fully define the multi-index set.\n", + "- Your function of interest should take a 2D array as input, where each row represents a point in multidimensional space and each column corresponds to a value in each dimension.\n", + "- When evaluating an interpolating polynomial, make sure your input has the same 2D array structure.\n", "\n", "While the example here is two-dimensional, the same principles apply to polynomials in higher dimensions.\n", "\n", @@ -1250,7 +1264,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/polynomial-bases-and-transformations.ipynb b/docs/getting-started/polynomial-bases-and-transformations.ipynb index d3828485..bbd660ea 100644 --- a/docs/getting-started/polynomial-bases-and-transformations.ipynb +++ b/docs/getting-started/polynomial-bases-and-transformations.ipynb @@ -10,7 +10,9 @@ }, "tags": [] }, - "source": "# Polynomial Bases and Transformations" + "source": [ + "# Polynomial Bases and Transformations" + ] }, { "cell_type": "markdown", @@ -23,13 +25,14 @@ "tags": [] }, "source": [ - "The Minterpy polynomials you've encountered so far have been represented in the Lagrange and Newton bases.\n", - "Minterpy supports a range of polynomial bases, each with a consistent interface, meaning that polynomials in different bases behave and can be manipulated in similar ways.\n", + "Up until now, you've encountered Minterpy polynomials represented in the Lagrange and Newton bases.\n", + "Minterpy supports a range of polynomial bases, all of which share a consistent interface.\n", + "This means that regardless of the basis, polynomials can be manipulated and behave in a similar manner, making it easy to switch between different representations.\n", "\n", "In this in-depth tutorial, you'll explore:\n", "\n", - "- various polynomial bases supported by Minterpy\n", - "- transformation between bases\n", + "- Various polynomial bases supported by Minterpy;\n", + "- Transformation between those bases.\n", "\n", "For simplicity, this tutorial uses examples in one and two dimensions, but the principles apply to polynomials of higher dimensions as well.\n", "\n", @@ -70,7 +73,7 @@ "source": [ "## Polynomials in Minterpy\n", "\n", - "Polynomials in Minterpy are multidimensional polynomials defined on $[-1, 1]^m$ where $m$ is the spatial dimension:\n", + "Polynomials in Minterpy are multivariate polynomials defined on $[-1, 1]^m$ where $m$ is the spatial dimension:\n", "\n", "$$\n", "Q(\\boldsymbol{x}) = \\sum_{\\boldsymbol{\\alpha} \\in A} c_{\\cdot, \\boldsymbol{\\alpha}} \\Psi_{\\cdot, \\boldsymbol{\\alpha}} (\\boldsymbol{x}),\n", @@ -105,7 +108,7 @@ "source": [ "### Lagrange basis\n", "\n", - "The Lagrange basis was the first polynomial basis you encountered in this series of tutorials. In Minterpy, the multidimensional Lagrange basis polynomial associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as a polynomial that satisfies the following condition:\n", + "The Lagrange basis was the first polynomial basis you encountered in this series of tutorials. In Minterpy, the multivariate Lagrange basis polynomial associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as a polynomial that satisfies the following condition:\n", "\n", "$$\n", "\\Psi_{\\mathrm{lag}, \\boldsymbol{\\alpha}} (\\boldsymbol{p}_{\\boldsymbol{\\beta}}) = \\delta_{\\boldsymbol{\\alpha}, \\boldsymbol{\\beta}}, \\;\\; \\boldsymbol{p}_{\\boldsymbol{\\beta}} \\in P_{A}, \\;\\; \\boldsymbol{\\alpha}, \\boldsymbol{\\beta} \\in A,\n", @@ -122,12 +125,12 @@ "Specifically, the coefficient corresponding to the multi-index element $\\boldsymbol{\\alpha}$ of an interpolating polynomial approximating a function $f$ is\n", "\n", "$$\n", - "c_{\\mathrm{lag}, \\boldsymbol{\\alpha}} = f(\\boldsymbol{p}_{\\boldsymbol{\\alpha}}).\n", + "c_{\\mathrm{lag}, \\boldsymbol{\\alpha}} = f(\\boldsymbol{p}_{\\boldsymbol{\\alpha}}), \\;\\; \\boldsymbol{p}_{\\boldsymbol{\\alpha}} \\in P_{A}, \\;\\; \\boldsymbol{\\alpha} \\in A,\n", "$$\n", "\n", "In other words, the coefficients are simply the values of the function at the unisolvent nodes.\n", "\n", - "To do more with polynomials in the Lagrange basis, such as evaluation or manipulation, you need to transform them to another basis. This process will be covered in a later section of this tutorial." + "To do more with the polynomials, such as evaluation or manipulation, you need to transform them to another basis. This process will be covered in a later section of this tutorial." ] }, { @@ -143,10 +146,10 @@ "source": [ "### Newton basis\n", "\n", - "You've also seen the Newton basis by following these tutorials. The multidimensional Newton basis polynomial associated with multi-index element $\\alpha$ is defined as:\n", + "You've also seen the Newton basis by following these tutorials. The multivariate Newton basis polynomial associated with multi-index element $\\alpha$ is defined as:\n", "\n", "$$\n", - "\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}} (\\boldsymbol{x}) = \\prod_{j = 1}^m \\prod_{i = 0}^{\\alpha - 1} (x_j - p_{i, j}),\n", + "\\Psi_{\\mathrm{nwt}, \\boldsymbol{\\alpha}} (\\boldsymbol{x}) = \\prod_{j = 1}^m \\prod_{i = 0}^{\\alpha_j - 1} (x_j - p_{i, j}),\n", "$$\n", "\n", "where $p_{i, j}$'s are the interpolation points along dimension $j$ (i.e., the so-called {ref}`generating points / nodes ` which in multiple dimensions are not the same as the unisolvent nodes).\n", @@ -197,14 +200,14 @@ "source": [ "### Canonical basis\n", "\n", - "The canonical basis is arguably the most familiar polynomial basis of them all. The multidimensional canonical basis polynomial associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as:\n", + "The canonical basis is arguably the most familiar polynomial basis of them all. The multivariate canonical basis polynomial associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as:\n", "\n", "$$\n", "\\Psi_{\\mathrm{can}, \\boldsymbol{\\alpha}} (\\boldsymbol{x}) = x_1^{\\alpha_1} \\cdots x_m^{\\alpha_m} = \\prod_{j = 1}^m x_j^{\\alpha_j}.\n", "$$\n", "\n", "```{warning}\n", - "While polynomials in the canonical basis can be evaluated at a set of query points, high-degree polynomials in the canonical basis in Minterpy become numerically unstable to evaluate and therefore is not recommended.\n", + "Although polynomials in the canonical basis can be evaluated at a set of query points, it's essential to note that high-degree polynomials in the canonical basis can become numerically unstable when evaluated. As a result, we strongly advise against using the canonical basis for high-degree polynomials due to potential numerical issues.\n", "```\n", "\n", "As an example, consider the two-dimensional multi-index set:\n", @@ -238,15 +241,15 @@ "source": [ "### Chebyshev basis\n", "\n", - "The multidimensional Chebyshev basis polynomial (of the first kind) associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as:\n", + "The multivariate Chebyshev basis polynomial (of the first kind) associated with the multi-index element $\\boldsymbol{\\alpha}$ is defined as:\n", "\n", "$$\n", "\\Psi_{\\mathrm{cheb}, \\boldsymbol{\\alpha}} (\\boldsymbol{x}) = T_{\\alpha_1} (x_1) \\cdots T_{\\alpha_m} (x_m) = \\prod_{j = 1}^m T_{\\alpha_j} (x_j),\n", "$$\n", "\n", - "where $T_{\\alpha_j} (x_j)$ is the $\\alpha_j$th-degree (one-dimensional) Chebyshev polynomial of the first kind associated with the $j$th-dimension.\n", + "where $T_{\\alpha_j} (x_j)$ is the $\\alpha_j$th-degree univariate Chebyshev polynomial of the first kind associated with the $j$th-dimension.\n", "\n", - "The one-dimensional Chebyshev polynomial of the first kind satisfies the following three-term recurrence (TTR) relation:\n", + "The univariate Chebyshev polynomial of the first kind satisfies the following three-term recurrence (TTR) relation:\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -325,7 +328,7 @@ "Consider the following one-dimensional polynomial:\n", "\n", "$$\n", - "Q(x) = 10 + 4.5 x - 3 x^2 + 1.5 x^3 - 1.2 x^4, x \\in [-1, 1].\n", + "Q(x) = 5 + 2.5 x - 2.0 x^2 - 5.0 x^3 + 1.0 x^4, x \\in [-1, 1].\n", "$$\n", "\n", "This polynomial is readily expressed in the canonical basis." @@ -372,7 +375,7 @@ "tags": [] }, "source": [ - "Then store the coefficients in an array:" + "Then store the coefficients in an array with the order that corresponds to the above multi-index set:" ] }, { @@ -388,7 +391,7 @@ }, "outputs": [], "source": [ - "coeffs_1d = np.array([5., 2.5, -2, -5, 1.])" + "coeffs_1d = np.array([5., 2.5, -2., -5., 1.])" ] }, { @@ -484,7 +487,7 @@ "tags": [] }, "source": [ - "The one-dimensional canonical basis polynomial are shown in the plots below." + "The univariate canonical basis polynomial are shown in the plots below." ] }, { @@ -1191,7 +1194,7 @@ "tags": [] }, "source": [ - "Because the function is not a polynomial (a square root is involved), creating a polynomial that approximates the function is much more intuitive in the Lagrange basis. In the other basis, it is not straightforward to intuit what the coefficient values should be." + "Since the function involves a square root and therefore is not a polynomial, constructing a polynomial approximation is much more intuitive in the Lagrange basis. In contrast, it's not immediately clear what the coefficient values should be in other bases, making the Lagrange basis a more natural choce for this type of approximation." ] }, { @@ -1205,7 +1208,7 @@ "tags": [] }, "source": [ - "First, create a two-dimensional multi-index of specified degree:" + "First, create a two-dimensional multi-index with the following choices of $n$ and $p$:" ] }, { @@ -1255,7 +1258,7 @@ "# Interpolation grid\n", "grd_2d = mp.Grid(mi_2d)\n", "# Coefficients of the Lagrange polynomial\n", - "coeffs_2d = grd_2d(fun)" + "lag_coeffs_2d = grd_2d(fun)" ] }, { @@ -1285,7 +1288,7 @@ }, "outputs": [], "source": [ - "lag_poly_2d = mp.LagrangePolynomial.from_grid(grd_2d, coeffs_2d)" + "lag_poly_2d = mp.LagrangePolynomial.from_grid(grd_2d, lag_coeffs_2d)" ] }, { @@ -1581,7 +1584,7 @@ "source": [ "### In the (2D) Newton basis\n", "\n", - "You can transform a Minterpy polynomial in the Lagrange basis to another polynomial in the Newton with the help of {py:class}`LagrangeToNewton <.transformations.lagrange.LagrangeToNewton>`:" + "You can transform a Minterpy polynomial in the Lagrange basis to another polynomial in the Newton basis with the help of {py:class}`LagrangeToNewton <.transformations.lagrange.LagrangeToNewton>`:" ] }, { @@ -2593,12 +2596,13 @@ ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "3d20a42e4ebc930b", + "metadata": {}, "source": [ "## From interpolant to interpolating polynomial\n", "\n", - "The {doc}`Quickstart Guide ` introduced\n", + "The {doc}`Quickstart Guide ` introduced\n", "you with the {py:func}`interpolate() <.interpolation.interpolate>` function to\n", "conveniently create an interpolant out of a function for a given spatial\n", "dimension, polynomial degree, and $l_p$-degree.\n", @@ -2614,8 +2618,7 @@ "| {py:meth}`to_lagrange() <.interpolation.Interpolant.to_lagrange>` | {py:class}`LagrangePolynomial <.polynomials.lagrange_polynomial.LagrangePolynomial>` |\n", "| {py:meth}`to_canonical() <.interpolation.Interpolant.to_canonical>` | {py:class}`CanonicalPolynomial <.polynomials.canonical_polynomial.CanonicalPolynomial>` |\n", "| {py:meth}`to_chebyshev() <.interpolation.Interpolant.to_chebyshev>` | {py:class}`CanonicalPolynomial <.polynomials.chebyshev_polynomial.ChebyshevPolynomial>` |" - ], - "id": "3d20a42e4ebc930b" + ] }, { "cell_type": "markdown", @@ -2632,9 +2635,9 @@ "\n", "In this tutorial, you've explored the different polynomial bases supported by Minterpy. Depending on the problem at hand, it may be more intuitive to construct a polynomial in a specific basis.\n", "\n", - "Once a polynomial has been constructed in one basis, it can be transformed into another. The result of this transformation is a polynomial that is equivalent to the original but represented in a different basis.\n", + "One of the powerful features of Minterpy is the ability to transform a polynomial from one basis to another. This transformation produces a new polynomial that is mathematically equivalent to the original, but expressed in a different basis.\n", "\n", - "Note, however, that Minterpy has different supported features for each polynomial basis as summarized by the following table.\n", + "Keep in mind that Minterpy's supported features vary across different polynomial bases. The following table provides a summary of the available features for each basis.\n", "\n", "| Operations | Lagrange | Newton | Canonical | Chebyshev |\n", "|:----------------------------------|:--------:|:--------:|:---------:|:---------:|\n", @@ -2651,13 +2654,13 @@ "\n", "---\n", "\n", - "So far, you've learned:\n", + "To recap, you've now acquired a solid foundation in working with Minterpy polynomials, including:\n", "\n", - "- how to construct Minterpy polynomials in one or more dimensions\n", - "- what operations you can perform with Minterpy polynomials (arithmetic and calculus operations)\n", - "- the different polynomial bases and how to transform between them\n", + "- Constructing polynomials in {doc}`one <1d-polynomial-interpolation>` or {doc}`more ` dimensions;\n", + "- Performing various operations with polynomials, such as {doc}`arithmetic ` and {doc}`calculus ` operations;\n", + "- Understanding the different polynomial bases and transforming between them (_this tutorial_).\n", "\n", - "In all these tutorials, you typically start with a given function of interest, where you can evaluate it at chosen locations (i.e., the unisolvent nodes) to construct an interpolating polynomial.\n", + "In all these tutorials, you typically start with a given function of interest, where you can evaluate it at specifically chosen locations (i.e., the unisolvent nodes) to construct an interpolating polynomial.\n", "\n", "One important problem remains: _How do you construct a polynomial from a given set of scattered data?_" ] @@ -2679,7 +2682,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/getting-started/polynomial-regression.ipynb b/docs/getting-started/polynomial-regression.ipynb index e732f8fc..96da9ab1 100644 --- a/docs/getting-started/polynomial-regression.ipynb +++ b/docs/getting-started/polynomial-regression.ipynb @@ -25,8 +25,8 @@ "tags": [] }, "source": [ - "The polynomials you've encountered so far in these tutorials are interpolating polynomials designed to approximate functions of interest based on values at specific, strategically chosen points known as the unisolvent nodes.\n", - "This also means that you have the flexibility to evaluate the function at these chosen points within its domain.\n", + "The polynomials you've worked with in these tutorials are designed to approximate functions of interest by using values at specific, strategically chosen points that form unisolvent nodes.\n", + "This implies that you have the flexibility to evaluate the function at these selected points within its domain.\n", "\n", "However, situations may arise where function values are available only at arbitrary, scattered points across the domain.\n", "In such cases, you cannot select the evaluation points freely.\n", @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "e79dfcd0-a294-4cfe-9e67-7fb88eeb4579", "metadata": { "editable": true, @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "5f86db01-c589-4155-8b05-576c046ac8d7", "metadata": { "editable": true, @@ -153,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "d173cf3e-6f8b-4941-8008-2139920c68f8", "metadata": { "editable": true, @@ -185,7 +185,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "0294c557-31a5-4468-88c5-575e413b1453", "metadata": { "editable": true, @@ -196,7 +196,18 @@ "hide-input" ] }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1EAAAGGCAYAAACaIQsUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydeXxU1fn/3/fOlkkymewJIQHCjiCriiAuuNcVq3WpVUGrfuteXCpqRaxWW9cWca0IVq3tDyu1aq2KuAJShYDIqgQSSCD7ZDL73Ht+fwxzmckC2RPCeb9eeUHOvffccyeTyf3c53k+jyKEEEgkEolEIpFIJBKJpFWoPb0AiUQikUgkEolEIjmUkCJKIpFIJBKJRCKRSNqAFFESiUQikUgkEolE0gakiJJIJBKJRCKRSCSSNiBFlEQikUgkEolEIpG0ASmiJBKJRCKRSCQSiaQNSBElkUgkEolEIpFIJG1AiiiJRCKRSCQSiUQiaQNSREkkEolEIpFIJBJJG5AiSiKRSCQSiUQikUjagBRREolEIpFIJBKJRNIGpIg6DAiFQjzwwAMMGzYMm82GoigsXbq0p5fVJezYsQNFUZg5c2aPrkMIwaRJkzj99NOb3V5eXs6VV15Jv379MJvNKIqC2Wzm2Wef7eaVSiQSiUQikUjairmnF3A44PF4+NOf/sSSJUvYunUroVCIrKwsCgsLmTZtGr/85S8ZMmRIl53/iSeeYN68eZxwwglcfPHFWCwWRo4c2WXn6wt8+umnTJ8+nblz5/LAAw+0+fhXX32VNWvWsHLlyibbdF3n7LPPZv369VxyySUMGTIEVVVZt24d8+bN44orrsDhcHTCVUgkEolEIpFIugIporoYt9vNtGnTWL9+PUOHDuUXv/gFGRkZVFVVsXr1ah599FGGDBnSpSLq3XffJTk5mY8++gir1dpl55FE0HWdBx54gOOPP55jjz22yfbPPvuMtWvXctNNNzF//nxj/LvvvmPs2LH8+c9/5t577+3OJUskEolEIpFI2oAUUV3M008/zfr16/nlL3/Jiy++iKIocduLi4sJBAJduoaysjIyMjKkgOom/vOf/7Bjx44WhdDy5csBmDFjRtz4kUceydixY3nppZeYM2cOqiqzbSUSiUQikUh6I/IurYuJpnPdeOONTQQUQGFhYVxq3aJFi1AUhUWLFjXZ99NPP0VRlLj0stixFStWcPrpp5OammqMKYpCcXExO3fuRFEUFEVh0KBBAASDQebPn88ZZ5xBQUEBNpuN7OxsfvrTn7J27doWr+nzzz9nxowZ5OTkYLPZKCgo4Kc//Slffvlls/uee+65ZGZmYrPZGDZsGPfddx9er7dVr1/s9X355ZecdNJJOBwOUlNTufDCC/nhhx9aNU+UV155hcmTJ5OcnExycjKTJ09u8lo/8MADTJ8+HYB58+YZr5uiKOzYsaNV51AUhQsvvDBu/K9//SuKovC73/0OgFNPPRVFUXA6ncY+F198MTt37jSElkQikUgkEomk9yEjUV1MRkYGAFu3bmX8+PFddp4VK1bw+9//nunTp3PddddRUlLCSSedBESiYQC33XYbAKmpqQDU1NRw2223cfzxx3PWWWeRlpbG9u3beeedd/jPf/7D559/ztFHHx13nj/96U/8+te/xm63c8EFFzBgwAB2797Nl19+yZIlS5g2bZqx73PPPceNN95Iamoq5557LtnZ2XzzzTc8/PDDLF++nOXLl7c6OrZq1SoeeeQRzjzzTG6++Wa+//573n77bb744gtWrVrF4MGDDzrHLbfcwvz58+nfvz/XXHMNAG+99RazZs1i7dq1/OlPfwLgpJNOYseOHSxevJgTTzzReB1jX7uWEEKwfPlyRowYQVpaWty2gQMHMnfuXB5//HHsdjs33ngjADk5OcY+U6ZMAWDZsmWccsopB70miUQikUgkEkkPICRdyr/+9S8BCIfDIW6//Xbx3//+V1RVVbW4/yuvvCIA8corrzTZtnz5cgGIuXPnNhkDxMKFC5udc+DAgWLgwIFNxv1+v9i1a1eT8Q0bNojk5GRx6qmnxo0XFRUJVVVFXl6eKC4ujtum67rYvXu38f33338vzGazGDduXJPrfeSRRwQgHn/88WbXG0vs9T3//PNx255//nkBiHPOOccYKy4uFoC46qqr4vb97LPPBCBGjRol6urqjPGamhoxfPhwAYjPP/+8yXljX+vW8P333wtAXH755c1ud7lcQlGUuDU33g6IE044oU3nlUgkEomkM2np72l3ouu6mDhxojjttNNa3KesrExcccUVIjc3V5hMJgEIk8kkFixY0I0rlRyOyHS+Lua8887jiSeeQAjBE088wRlnnEFmZiZDhw7lpptuYtu2bZ1ynokTJzJr1qw2HWOz2ejfv3+T8dGjRzN9+nQ+//xzQqGQMf7CCy+g6zoPPfSQkRIYRVEU8vLy4vYNh8PMnz/fiMZFueuuu8jKyuJvf/tbq9c6fPhwrr322rixa6+9lmHDhvHee+9RWVl5wOMXL14MRFL1YtPn0tLSmDt3LkCzKZRtZdeuXUB8dCmWoqIihBBMmDCh2e0pKSkkJCQY80gkEokEvv32W6655hqGDRtGUlISdrudIUOGcMUVV/DRRx912zqaS6uXtExHX6+o0+2DDz7Y7Pao2+0bb7zBySefzD333MPcuXM599xzmTdvHm63uwOrl0gOjEzn6wZmz57NtddeywcffMCKFSv45ptv+Prrr1mwYAEvv/wyf//73znvvPM6dI7GaXetpaioiD/+8Y98+eWX7NmzJ040AVRVVdGvXz8AVq9eDdBi76NYVq1aBcB///tfli1b1mS7xWJh8+bNrV7ncccd18RoQVVVjjvuOLZt28a6des49dRTWzw+WuMVm5oXJVr/VFRU1Or1tER1dTXQctpfdB0HSu1MT0+nqqqqw2uRSCSSQx1d17njjjt46qmnMJvNnHzyyZx33nlYLBa2b9/Oe++9x2uvvcaDDz7Ib3/7255erqQTOZjTLUi3W0nPIkVUN+FwOPjZz37Gz372MwBcLhf33HMPzz77LNdccw27d+/ukHteS5GPA7FixQpOPvlkICKMhg0bRnJystGMd926dXHOgS6XC0VRDFF1IGpqagB4+OGH27yu5mjp+qLjLpfrgMfX19ejqipZWVnNzqEoCvX19R1ep91uB8Dv9ze7PSrUDiSifD4fiYmJHV6LRCKRHOrcd999PPXUU4wfP54lS5Y0aQfi8/l45plnjAdYkr7DwZxuQbrdSnoW+a7qIZxOJ8888wwDBw6kqqqK7777DsD4RQ+Hw02OOZBQaM7572A8/PDDBAIBPv74Y9555x2jKe8DDzxAbm5uk/1TU1MRQlBeXn7QuVNSUoCIeBFCtPjVWvbu3XvA8dgUvZbWo+t6s2l/FRUVCCGMNXeEqEiLisjGrF27FqfTSWFhYbPbdV3H5XI1K/YkEonkcOKHH37gj3/8IxkZGXzwwQfN9lO02+3ceeedzJs3L268NU6sEJ9u9s0333DaaafhcDhwOp1ccMEFcY6sbXFube35O9OR92B0ptttTzrdgnS7lfQOpIjqQRRFISkpKW4s6ui2e/fuJvsfyHa8Pfz444+kp6fHOeoBeL1e1qxZ02T/Y445BoAPP/zwoHNPnjwZ2J/W11G++uordF2PG9N1nRUrVqAoCuPGjTvg8dEapE8//bTJtuhYbHTIZDIBoGlam9Y5evRoVFVly5YtTbYFg0E2btzIuHHjWvyDt23bNnRd58gjj2zTeSUSiaSvsWjRIjRN4/rrrz9otoXNZjP+f8stt3D11Veze/durrnmGiPbY9asWdx6663NHv+///2PE044AavVyvXXX89RRx3F0qVLOfXUU43MgpNOOomrrroKgBNPPJG5c+caX7Ep3O05f1tZsWIFJ510EoqicN1113HJJZe0+thVq1Zxyimn4HQ6ufnmmznxxBN5++23mTp1Ktu3bz/o8a29vta+Xs0hDuB0C/vdbpOSksjMzDTmffTRR419Yt1uJZIuoWf8LA4fnn/+ebF69epmt7399ttCURSRmpoq/H6/EEKI3bt3C0VRxMiRI4XP5zP23bp1q0hNTW3Rne9ALnItufOdfvrpQlEUsWHDBmMsHA6LX/3qV4YjXqwL3/r164XJZBJ5eXlix44dcXM1duf77rvvhNlsFiNGjBA7d+5scu7a2lqxZs2aFtfc+ProJHe+I444QrhcLmO8rq5OjBw5UgDis88+M8Y3bNjQblei8ePHC4fDITRNixv/9ttvBSBuvfXWFo9dvHixAMQLL7zQ5vNKJBJJX+Kkk04SgPj4449bfUx7nVgB8eabb8bNdcUVVwhA/O1vf2uyf0t/c9t6/q5w5G2Jzvh72lucboWQbreSnkdGorqY//znPxxzzDEMGzaMmTNncs8993DrrbdywgkncMEFF6AoCs8++6zxFC0vL4/LLruMzZs3M2nSJG6//XauuOIKJkyY0Ol9g26++WaEEEybNo3rr7+eW2+9lYkTJ/KPf/yjWQOGI488kqeffpry8nJGjx7NL37xC+69916uueYahg8fzh//+Edj3zFjxvDss8/yww8/MGLECC688ELuuusufvWrX3HGGWeQm5vLCy+80Oq1nnHGGdxyyy2cf/753HPPPZx//vn86le/IjMz0+jvdCBOOOEEbr75ZjZu3MiYMWP49a9/zW233caYMWPYvHkzt9xyCyeccIKx/8iRI8nLy+PNN9/k+uuv53e/+x0PPfTQQWuvAC644ALcbneTKFxrTCU++ugjzGYz55xzzkHPI5FIJH2ZPXv2AJCfn9/qY9rrxHrCCSc0ieZcffXVQCRK1dXnbyvtceSN0hG3297idAvS7VbS80gR1cX84Q9/4I9//COFhYV8/vnnPPXUU7z44ouUlZVx1VVXsXr1ai677LK4Y/7yl79wyy23UF1dzYIFC1i/fj0vvvgiN910U6eu7ZxzzmHJkiUMHjyY1157jTfeeIORI0eyevVqBg4c2OwxN910E5988gnTp0/nP//5D48//jgffvgh48aN4+KLL47b99prr2XlypXMmDGDVatW8fTTT7NkyRKqqqoMEdNajj32WJYtW4bL5eLPf/4zn376KTNmzGDlypWtarQL8Oc//5mFCxeSm5vLiy++yEsvvUS/fv1YuHBhEyFmMpn45z//ybHHHsvf/vY37r//fn77299SW1t70PP88pe/xGw289prr8WNH0xEeb1eli5dyjnnnBNnFy+RSCSS1tFeJ9ZJkyY1GYuKt7q6ui4/f1tpryMvHNjtVgjBunXrWjy2tzjdxq5Fut1KegrpztfFjBgxgjvvvJM777yz1cfY7Xb+9Kc/NRthEY3MGE466aSDGjQcqIDzwgsvbLZoc9GiRS0+TTrppJOa/QBtjqOPPrpN/aAOxLRp05qtaYpl0KBBB3w9Zs2a1eqnd5MnTz7o+ZojLy+PSy+9lDfffJM//OEPOBwOAJ555hmeeeaZFo974403aGho4Ne//nWbzymRSCR9jdzcXDZv3szu3bsZMWJEq45prxNrc8ZCZnPkFqkttbHd5QTbHkfegx3bGrfb3uJ0C9LtVtLzyEiURNIFPPTQQ/h8vri+FQciHA7z+9//nvPOOy8urVAikUgOV4477jigbcYA3eXE2lnn705H3igdcbvtLU63IN1uJT2PFFESSRcwcOBAFi9ebEShDkZJSQlXXnklTz75ZBevTCKRSA4NZs6ciclk4sUXXzxgnQ5g9DRsqxNrWzmYc2tbz9+djrxROuJ22xucbkG63Up6B1JESSRdxMUXX8zNN9/cqn0HDx7MAw880GwfFIlEIjkcGTp0KHfddRdVVVX85Cc/obi4uMk+fr+fJ5980uilFLXUnjdvXlxamcvlMnpJRfdpD+np6QCUlpY2u72t5580aRKKovDmm2/Gpa5t27atVaZJ7WHr1q289NJLcWMvvfQSW7du5eyzzz5g5Kat13ew16slUlNTGTt2LN98800TwQewYcMGQqFQi6YSAF9//TUQsVeXSLoCWRMl6dW0puZLIpFIJH2Thx56CL/fz1NPPcWIESM4+eSTGTNmDBaLheLiYj7++GOqq6t56KGHgP1OrPPnz2fMmDFceOGFCCF466232LVrVxMn1rYS69xqs9nIz89HURRuvvlmnE5nm88fdeR94403mDRpEmeeeSYVFRW8/fbbnHnmmbz11lsdfg0bE3W7ff/99xk9ejTff/89//73v1vldtvW6zvY63UgLrjgAubOncuqVauYOnVq3DbpdivpFfSIsbpEIpFIJBJJK/nf//4nrr76ajF06FBht9uFzWYTgwYNEj//+c/FRx991GT/hQsXiqOPPlokJiaKxMREcfTRRzfbV+lAfYxa6ju4atUqceKJJwqHw9FsT8W2nF8IIbxer7jllltETk6OsNlsYuzYseL1118/YJ+otvZdanzsF198IU488USRlJQkUlJSxAUXXCC2bdvWqutv6/W15vVqjt27dwuz2Sx+9atfNdl24403CkCsXbu22WM9Ho9ITk4WM2bMOOh5JJL2ogghH/NLJBKJRCKR9GU+/fRTpk+fzty5c430x97OFVdcwXvvvcfOnTtbXWMMkVYx1157LZ999pk0a5J0GbImSiKRSCQSiUTS62ir0y1It1tJ9yFFlEQikUj6BA0NDcydO5czzzyT9PR0FEVpsd9dc9TV1XHdddeRlZVFUlIS06dPZ82aNc3u+8477zBx4kQSEhIYMGAAc+fObdamWiKRtJ+2Ot2CdLuVdB/SWEIikUgkfYKqqioefPBBBgwYwLhx49rULFvXdc4++2zWrVvHnXfeSWZmJs8++ywnnXQS3377LcOGDTP2/c9//sOMGTM46aSTmD9/Pt999x0PPfQQFRUVPPfcc11wZRLJ4cvFF1/cpv2jbrcSSVcjI1ESiUQi6RP069eP8vJydu7cyWOPPdamY5csWcKKFStYtGgRc+fO5cYbb+TTTz/FZDIxd+7cuH3vuOMOxo4dy4cffsi1117Ln//8Z+bMmcMLL7zA5s2bO/OSJJJOI+p2KwWGpDewYMECBg0aREJCApMnT2b16tWtOu7NN99EURRmzJgRN97Q0MBNN91Efn4+drudI444gueff74LVr4fKaIkEolE0iew2Wzk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p1RPb5YrX/o1ezk1oiwWC+Xl5axZs4Zt27axZs0aLBYLAwMD7Nixg3379tHb20sgEDinwtI5d77Xlp5//nmuuuoq/t//+3984hOfyOqLx+Pcd9991NXV8aUvfemS7620tJTReTc10kq3lZUtfeHg9Xoxm81nNba0tBRFURZlkUomk0xPT59xjVezcvCU09nqYsYrvZJZCi80PC3UmepFpQHqQhXanegqvyDzvByZTCY2bNiQ5RquqipPPvkkW7ZsOe95r7jiCk6dyk5e1tnZSXV19XnP+VJaFu58k5OTmfpJgiBk3CcutNKWqAsdTB8OhzNv3IWK30or4ybYfJMe/5SOgUIHKTUcyrQJpatA01CPPola2IIgCLr73lAH6qzFSShfiTovhkkobdYzIHZ28pOf/oSfPncILRxBSRgYHBzgP/7jfg60H0A+9CyUtSCKItaGNopTQepNKvleL1ppA7FolLH9LzC2fyehUIhUKoXcp2fZU/o7M9nr0pL7OhHKmpB7Z2s7CQKitwSxogkG+zEaDEiiiFDRgKZppHq6kGWZVE8n4tqtyLJM7FRH1px+Zz6pHn2+NEClgUQez67zIlXPWnW6exe06+MSXQNZrnYAptfdkDle7u1BqmkANFLFlSR7+pHnpVKXe3qRahqQahrJz8/nb7ZeweW3/WXGXW1LeQW2LVexcf0G5J6+efPNvi/eIqTqOpLz9pful6obM/ucrwtZaFcURfLy8qivr+eyyy7jiiuuoKKiglgsxuHDh9mxYwfHjh1jZGRkybv3aZ1tYglVVYlGozmIehXI6XTy+OOPc/vtt/OZz3yGe+65h2QyyQMPPEBDQwMf//jHEUWRz3/+85d8b21tbXR2di5K2LBnz55M/1ISRfGM9UT27NlDXV1d5rubnmPhsfv370dV1TOu8WpUDp5yOlddzHilVypL4cWEp/laql7UN2/ZcEEAaqKrfFkAVFof+chHeOCBB3jooYc4efIkH/jAB4hEItx9990A3HnnnVmugMlkkkOHDnHo0CGSySTDw8McOnSI7u45z6cPf/jD7N69m89+9rN0d3fz8MMP861vfYu/+Zu/uWjn8YpClKZpdHV1cejQIVauXElTU9NFgZy00hdzF9Klb3Jykt27d+PxeDAajRiN+lipXAAA7NdJREFUFzbob74lSlh1Y1afOnQSLHmog3q9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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "from mpl_toolkits.axes_grid1 import make_axes_locatable\n", "\n", @@ -296,7 +307,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "603eaf0b-1b4f-4686-9e4e-c0a0a017c675", "metadata": { "editable": true, @@ -326,7 +337,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "0b1bf99a-e689-4d1e-a206-799643f8dcc9", "metadata": { "editable": true, @@ -335,7 +346,18 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "58" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "len(mi)" ] @@ -372,7 +394,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "0d509374-46e1-4c25-abac-7ffb2e7bc4d3", "metadata": { "editable": true, @@ -415,12 +437,12 @@ "source": [ "### Fit the regression polynomial\n", "\n", - "You have so far constructed a regression polynomial by defining the structure of the underling polynomial. For now, however, its coefficients remain unknown." + "You have so far constructed a regression polynomial by defining the structure of the underlying polynomial. For now, however, its coefficients remain unknown." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "f977b3b2-9db1-43b1-9656-65efd0be74c7", "metadata": { "editable": true, @@ -429,7 +451,18 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reg_poly.coeffs is None" ] @@ -451,7 +484,7 @@ "\\hat{\\boldsymbol{c}} = \\underset{\\boldsymbol{c}}{\\mathrm{arg min}} \\lVert \\boldsymbol{R} \\boldsymbol{c} - \\boldsymbol{y} \\rVert_2^2\n", "$$\n", "\n", - "where: $\\lVert \\cdot \\rVert_2^2$ denotes the square of the Euclidian norm.\n", + "where: $\\lVert \\cdot \\rVert_2^2$ denotes the square of the Euclidean norm.\n", "\n", "\n", "You can use the method {py:meth}`fit() <.extras.regression.ordinary_regression.OrdinaryRegression.fit>` to solve the above problem on the given regression polynomial instance.\n", @@ -460,7 +493,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "76174cad-e150-41dc-8deb-77322a2782cd", "metadata": { "editable": true, @@ -469,7 +502,16 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/wicaks72/projects/minterpy/dev/src/minterpy/schemes/barycentric/operators.py:50: UserWarning: building a full transformation matrix from a barycentric transformation. this is inefficient.\n", + " warn(\n" + ] + } + ], "source": [ "reg_poly.fit(xx_train, yy_train)" ] @@ -485,12 +527,12 @@ "tags": [] }, "source": [ - "Note that the call to `fit()` alters the instance in-place; once the call is concluded, the coefficients are available:" + "Note that the call to {py:meth}`fit() <.extras.regression.ordinary_regression.OrdinaryRegression.fit>` alters the instance in-place; once the call is concluded, the coefficients are available:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "e75466de-b2ea-4ed8-be95-0df98466c569", "metadata": { "editable": true, @@ -499,7 +541,19 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.11473161, 0.41097058, 0.24196861, -0.05085656, 0.42838383,\n", + " 0.37984464, 0.06996035, -0.10282655, 0.42058672, 0.41146145])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reg_poly.coeffs[:10] # the first 10" ] @@ -524,7 +578,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "4c271b0f-47f6-46f6-b7af-923dcc9b81e5", "metadata": { "editable": true, @@ -533,7 +587,18 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([-0.11748932, 0.3520634 , 0.35206581])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reg_poly(\n", " np.array([\n", @@ -574,7 +639,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "8b394e75-8da2-4900-b871-ebf2f9617b38", "metadata": { "editable": true, @@ -583,7 +648,24 @@ }, "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ordinary Polynomial Regression\n", + "------------------------------\n", + "Spatial dimension: 2\n", + "Poly. degree : 8\n", + "Lp-degree : 2.0\n", + "Origin poly. : \n", + "Error Absolute Relative\n", + "L-inf Regression Fit 2.57395e-06 1.77514e-05\n", + "L2 Regression Fit 8.05418e-13 3.83077e-11\n", + "LOO CV 2.59071e-10 1.23220e-08\n" + ] + } + ], "source": [ "reg_poly.show()" ] @@ -602,8 +684,10 @@ "The three measures of fitting error are:\n", "\n", "- Infinity norm (`L-inf`)\n", - "- Euclidian norm (`L2`)\n", - "- Leave-one-out cross validation error\n", + "- Euclidean norm (`L2`)\n", + "- Leave-one-out cross validation error (`LOO CV`)\n", + "\n", + "Note that for `L2` and `LOO CV` the errors are still squared.\n", "\n", "For `L2` and `LOO CV` the relative errors are the absolute errors normalized by the variance of the output in the dataset. For `L-inf` the relative error is the absolute error normalized by the standard deviation of the output in the dataset.\n", "\n", @@ -756,7 +840,7 @@ "source": [ "### Closing remark\n", "\n", - "Once fitted, a regression polynomial is fully determined. In particular, the `eval_poly` property of the instance is a Minterpy polynomial you've already familiar. You can carry out arithmetic as well as calculus operations on it." + "Once fitted, a regression polynomial is fully determined. In particular, the {py:meth}`eval_poly <.extras.regression.ordinary_regression.OrdinaryRegression.eval_poly>` property of the instance is a Minterpy polynomial you've already familiar. You can carry out arithmetic as well as calculus operations on it." ] }, { @@ -802,8 +886,7 @@ "source": [ "## Summary\n", "\n", - "In this tutorial, you've learned how to perform polynomial regression in Minterpy.\n", - "This is particularly useful when you have a dataset (pairs of inputs and outputs) but you may not have access to the underlying function.\n", + "In this tutorial, you’ve learned how to perform polynomial regression using Minterpy. This is particularly useful when working with a dataset consisting of input–output pairs, especially when the underlying function is unknown or inaccessible.\n", "\n", "Polynomial regression in Minterpy is facilitated through the {py:class}`OrdinaryRegression <.extras.regression.ordinary_regression.OrdinaryRegression>` class.\n", "The steps to construct a regression polynomial are as follows:\n", @@ -816,11 +899,11 @@ "Once fitted, the resulting instance is callable, allowing you to evaluate it at any set of query points by passing these points directly to the instance.\n", "\n", "Finally, you can also access the underlying fitted polynomial from the {py:meth}`eval_poly <.extras.regression.ordinary_regression.OrdinaryRegression.eval_poly>` property of the instance.\n", - "This polynomial is a Minterpy polynomial, so you can apply a variety of arithmetic and calculus operations on it, as covered in the previous tutorials.\n", + "This polynomial is a Minterpy polynomial, so you can apply a variety of {doc}`arithmetic ` and {doc}`calculus ` operations on it, as covered in the previous tutorials.\n", "\n", "---\n", "\n", - "Congratulations on completing the in-depth tutorials of Minterpy!\n", + "Congratulations on completing this series of Minterpy in-depth tutorials!\n", "\n", "You should now be familiar with the main features of Minterpy.\n", "We hope you find Minterpy valuable for your work!" @@ -843,7 +926,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.9.19" } }, "nbformat": 4, diff --git a/docs/index.rst b/docs/index.rst index cc4afd0c..3351bdfc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,8 +14,8 @@ Minterpy Documentation .. image:: /assets/Wordmark-color.png -Minterpy is an open-source Python package designed for constructing -and manipulating multidimensional interpolating polynomials with the goal of +Minterpy is an open-source Python package designed for constructing +and manipulating multivariate interpolating polynomials with the goal of lifting the curse of dimensionality from interpolation tasks. .. grid:: auto @@ -29,7 +29,7 @@ lifting the curse of dimensionality from interpolation tasks. :class-footer: sd-border-0 :shadow: None - Discover what Minterpy and multidimensional polynomials can do for you + Discover what Minterpy and multivariate polynomials can do for you through a series of practical tutorials. +++ .. button-ref:: getting-started/index @@ -102,9 +102,9 @@ lifting the curse of dimensionality from interpolation tasks. | -Minterpy is continuously extended and improved, with new functionalities added -to address the bottlenecks involving interpolations -in various computational tasks. +Minterpy is being continuously extended and improved, +with new functionalities added to address the bottlenecks +involving interpolations in various computational tasks. | diff --git a/joss/convergence.png b/joss/convergence.png new file mode 100644 index 00000000..5a90c072 Binary files /dev/null and b/joss/convergence.png differ diff --git a/joss/paper.bib b/joss/paper.bib new file mode 100644 index 00000000..3a47b929 --- /dev/null +++ b/joss/paper.bib @@ -0,0 +1,332 @@ +@Article{Dornheim2023, + author = {Dornheim, Tobias and Wicaksono, Damar and Suarez-Cardona, Juan E. and Tolias, Panagiotis and Böhme, Maximilian P. and Moldabekov, Zhandos A. and Hecht, Michael and Vorberger, Jan}, + journal = {Physical Review B}, + title = {Extraction of the frequency moments of spectral densities from imaginary-time correlation function data}, + year = {2023}, + number = {15}, + pages = {155148}, + volume = {107}, + doi = {10.1103/physrevb.107.155148}, + publisher = {American Physical Society (APS)}, +} + +@InProceedings{Schreiber2023, + author = {Schreiber, Janina and Wicaksono, Damar and Hecht, Michael}, + booktitle = {Proceedings of the Companion Conference on Genetic and Evolutionary Computation}, + title = {Minimizing black boxes due to polynomial-model-based optimization}, + year = {2023}, + pages = {759--762}, + series = {GECCO ’23 Companion}, + volume = {2}, + doi = {10.1145/3583133.3590743}, +} + +@Article{Veettil2023, + author = {Veettil, Sachin Krishnan Thekke and Zavalani, Gentian and Acosta, Uwe Hernandez and Sbalzarini, Ivo F. and Hecht, Michael}, + journal = {SIAM Journal on Scientific Computing}, + title = {Global polynomial level sets for numerical differential geometry of smooth closed surfaces}, + year = {2023}, + number = {4}, + pages = {A1995--A2018}, + volume = {45}, + doi = {10.1137/22m1536510}, +} + +@Article{Meijering2002, + author = {Meijering, E.}, + journal = {Proceedings of the IEEE}, + title = {A chronology of interpolation: from ancient astronomy to modern signal and image processing}, + year = {2002}, + number = {3}, + pages = {319--342}, + volume = {90}, + doi = {10.1109/5.993400}, +} + +@Article{Cools2002, + author = {Cools, Ronald}, + journal = {Journal of Computational and Applied Mathematics}, + title = {Advances in multidimensional integration}, + year = {2002}, + number = {1}, + pages = {1--12}, + volume = {149}, + doi = {10.1016/s0377-0427(02)00517-4}, +} + +@Article{Xiu2009, + author = {Xiu, Dongbin}, + journal = {Communications in Computational Physics}, + title = {Fast numerical methods for stochastic computations: a review}, + year = {2009}, + number = {2--4}, + pages = {242--272}, + volume = {5}, +} + +@Book{Trefethen2019, + author = {Trefethen, L. N.}, + publisher = {Society for Industrial and Applied Mathematics (SIAM)}, + title = {Approximation theory and approximation practice, extended edition}, + year = {2019}, + address = {Philadelphia, PA}, +} + +@Article{Branges1959, + author = {{de Branges}, Louis}, + journal = {Proceedings of the American Mathematical Society}, + title = {The {Stone}-{Weierstrass} theorem}, + year = {1959}, + number = {5}, + pages = {822--824}, + volume = {10}, + doi = {10.1090/s0002-9939-1959-0113131-7}, +} + +@Article{Trefethen2011, + author = {Trefethen, L. N.}, + journal = {Mathematics Today}, + title = {Six myths of polynomial interpolation and quadrature}, + year = {2011}, + pages = {184--188}, + volume = {47}, +} + +@Article{Trefethen2017, + author = {Trefethen, L. N.}, + journal = {SIAM Review}, + title = {Cubature, approximation, and isotropy in the hypercube}, + year = {2017}, + number = {3}, + pages = {469--491}, + volume = {59}, + doi = {10.1137/16m1066312}, +} + +@Book{Driscoll2014, + editor = {Driscoll, Tobin A. and Hale, Nicholas and Trefethen, Llyod N.}, + publisher = {Pafnuty Publications}, + title = {Chebfun guide}, + year = {2014}, + address = {Oxford}, + note = {Retrieved September 26, 2024}, + url = {https://www.chebfun.org/docs/guide/}, +} + +@Misc{Olver2023, + author = {Olver, Sheehan and Townsend, Alex and others}, + title = {{ApproxFun.j}l: a {Julia} package for function approximation}, + year = {2023}, + journal = {GitHub repository}, + publisher = {GitHub}, + url = {https://github.com/JuliaApproximation/ApproxFun.jl}, +} + +@Misc{Richardson2024, + author = {Richardson, Mark and others}, + note = {Retrieved September 26, 2024}, + title = {{ChebPy} - a {Python} implementation of {Chebfun}}, + year = {2024}, + journal = {GitHub repository}, + publisher = {GitHub}, + url = {https://github.com/chebpy/chebpy}, +} + +@Misc{Swierczewski2024, + author = {Swierczewski, Chris and Verdier, Olivier}, + note = {Retrieved September 26, 2024}, + title = {{pychebfun} - {Python} {Chebyshev} functions}, + year = {2024}, + journal = {GitHub repository}, + publisher = {GitHub}, + url = {https://github.com/pychebfun/pychebfun}, +} + +@Article{Feinberg2015, + author = {Feinberg, Jonathan and Langtangen, Hans Petter}, + journal = {Journal of Computational Science}, + title = {Chaospy: An open source tool for designing methods of uncertainty quantification}, + year = {2015}, + pages = {46--57}, + volume = {11}, + doi = {10.1016/j.jocs.2015.08.008}, +} + +@Article{Tate2023, + author = {Tate, Jess and Liu, Zexin and Bergquist, Jake A. and Rampersad, Sumientra and White, Dan and Charlebois, Chantel and Rupp, Lindsay and Brooks, Dana H. and MacLeod, Rob S. and Narayan, Akil}, + journal = {Journal of Open Source Software}, + title = {{UncertainSCI}: a {Python} package for noninvasive parametric uncertainty quantification of simulation pipelines}, + year = {2023}, + number = {90}, + pages = {4249}, + volume = {8}, + doi = {10.21105/joss.04249}, +} + +@Article{Weise2020, + author = {Weise, Konstantin and Poßner, Lucas and Müller, Erik and Gast, Richard and Knösche, Thomas R.}, + journal = {SoftwareX}, + title = {{Pygpc}: A sensitivity and uncertainty analysis toolbox for {Python}}, + year = {2020}, + pages = {100450}, + volume = {11}, + doi = {10.1016/j.softx.2020.100450}, +} + +@Article{Seshadri2017, + author = {Seshadri, Pranay and Parks, Geoffrey}, + journal = {The Journal of Open Source Software}, + title = {{Effective-Quadratures (EQ)}: polynomials for computational engineering studies}, + year = {2017}, + number = {11}, + pages = {166}, + volume = {2}, + doi = {10.21105/joss.00166}, +} + +@Article{Hegemann2023, + author = {Hegemann, Nando and Heidenreich, Sebastian}, + journal = {Journal of Open Source Software}, + title = {{PyThia}: a {Python} package for uncertainty quantification based on non-intrusive polynomial chaos expansions}, + year = {2023}, + number = {89}, + pages = {5489}, + volume = {8}, + doi = {10.21105/joss.05489}, +} + +@Article{Xiu2002, + author = {Xiu, Dongbin and Karniadakis, George Em}, + journal = {SIAM Journal on Scientific Computing}, + title = {The {Wiener--Askey} polynomial chaos for stochastic differential equations}, + year = {2002}, + number = {2}, + pages = {619--644}, + volume = {24}, + doi = {10.1137/S1064827501387826}, +} + +@Article{Virtanen2020, + author = {Virtanen, Pauli and Gommers, Ralf and Oliphant, Travis E. and Haberland, Matt and Reddy, Tyler and Cournapeau, David and Burovski, Evgeni and others}, + journal = {Nature Methods}, + title = {{SciPy} 1.0: fundamental algorithms for scientific computing in {Python}}, + year = {2020}, + number = {3}, + pages = {261--272}, + volume = {17}, + doi = {10.1038/s41592-019-0686-2}, + publisher = {Springer Science and Business Media {LLC}}, +} + +@Article{Margolis2019, + author = {Margolis, Benjamin and Lyons, Kenneth}, + journal = {Journal of Open Source Software}, + title = {{ndsplines}: a {Python} library for tensor-product {B-Splines} of arbitrary dimension}, + year = {2019}, + number = {42}, + pages = {1745}, + volume = {4}, + doi = {10.21105/joss.01745}, + publisher = {The Open Journal}, +} + +@Article{Trefethen2017a, + author = {Trefethen, L. N.}, + journal = {Proceedings of the American Mathematical Society}, + title = {Multivariate polynomial approximation in the hypercube}, + year = {2017}, + number = {11}, + pages = {4837--4844}, + volume = {145}, + doi = {10.1090/proc/13623}, +} + +@Misc{Veettil2022, + author = {Veettil, Sachin Krishnan Thekke and Zheng, Yuxi and Hernandez Acosta, Uwe and Wicaksono, Damar and Hecht, Michael}, + title = {Multivariate polynomial regression of {Euclidean} degree extends the stability for fast approximations of {Trefethen} functions}, + year = {2022}, + doi = {10.48550/arXiv.2212.11706}, + publisher = {arXiv}, +} + +@Article{Chkifa2013, + author = {Chkifa, Moulay Abdellah}, + journal = {Journal of Approximation Theory}, + title = {On the {Lebesgue} constant of {Leja} sequences for the complex unit disk and of their real projection}, + year = {2013}, + pages = {176--200}, + volume = {166}, + doi = {10.1016/j.jat.2012.11.005}, +} + +@Book{Goldstine1977, + author = {Goldstine, Herman H.}, + publisher = {Springer New York}, + title = {A history of numerical analysis from the 16th through the 19th century}, + year = {1977}, + isbn = {9781468494723}, + series = {Studies in the History of Mathematics and Physical Sciences}, + doi = {10.1007/978-1-4684-9472-3}, +} + +@Article{Trefethen2016, + author = {Trefethen, L. N.}, + journal = {Notices of the American Mathematical Society}, + title = {Inverse {Yogiisms}}, + year = {2016}, + number = {11}, + pages = {1281--1285}, + volume = {63}, + doi = {10.1090/noti1446}, + publisher = {American Mathematical Society (AMS)}, +} + +@Article{Breuss2018, + author = {Breuß, Michael and Kemm, Friedemann and Vogel, Oliver}, + journal = {Kybernetika}, + title = {A numerical study of {Newton} interpolation with extremely high degrees}, + year = {2018}, + pages = {279--288}, + doi = {10.14736/kyb-2018-2-0279}, +} + +@Article{Reichel1990, + author = {Reichel, Lothar}, + journal = {BIT}, + title = {Newton interpolation at {Leja} points}, + year = {1990}, + number = {2}, + pages = {332--346}, + volume = {30}, + doi = {10.1007/bf02017352}, +} + +@Article{TalEzer1991, + author = {Tal-Ezer, Hillel}, + journal = {SIAM Journal on Scientific and Statistical Computing}, + title = {High degree polynomial interpolation in {Newton} form}, + year = {1991}, + number = {3}, + pages = {648--667}, + volume = {12}, + doi = {10.1137/0912034}, +} + +@Misc{Wicaksono2025, + author = {Wicaksono, Damar Canggih and Hernandez Acosta, Uwe and Thekke Veettil, Sachin Krishnan and Kissinger, Jannik and Hecht, Michael}, + title = {{Data to "Minterpy: Multivariate polynomial interpolation in Python"}}, + year = {2025}, + doi = {10.14278/rodare.3379}, + url = {https://doi.org/10.14278/rodare.3379}, +} + +@Misc{Hecht2025, + author = {Hecht, Michael and Hofmann, Phil-Alexander and Wicaksono, Damar and Hernandez Acosta, Uwe and Gonciarz, Krzysztof and Kissinger, Jannik and Sivkin, Vladimir and Sbalzarini, Ivo F.}, + title = {Multivariate {Newton} interpolation in downward closed spaces reaches the optimal geometric approximation rates for {Bos}--{Levenberg}--{Trefethen} functions}, + year = {2025}, + archiveprefix = {arXiv}, + eprint = {2504.17899}, + url = {https://arxiv.org/abs/2504.17899}, +} + +@Comment{jabref-meta: databaseType:bibtex;} diff --git a/joss/paper.md b/joss/paper.md new file mode 100644 index 00000000..e07b2f73 --- /dev/null +++ b/joss/paper.md @@ -0,0 +1,371 @@ +--- +title: 'Minterpy: multivariate polynomial interpolation in Python' +tags: + - Python + - numerical computing + - function approximation + - polynomial interpolation + - polynomial regression +authors: + - name: Damar Wicaksono + orcid: 0000-0001-8587-7730 + equal-contrib: false + affiliation: "1" + - name: Uwe Hernandez Acosta + orcid: 0000-0002-6182-1481 + equal-contrib: false + affiliation: "1" + - name: Sachin Krishnan Thekke Veettil + orcid: 0000-0003-4852-2839 + equal-contrib: false + affiliation: "3" + - name: Jannik Kissinger + orcid: 0000-0002-1819-6975 + equal-contrib: false + affiliation: "3, 4" + - name: Michael Hecht + orcid: 0000-0001-9214-8253 + equal-contrib: false + affiliation: "1, 2" +affiliations: + - name: Center for Advanced Systems Understanding (CASUS) - Helmholtz-Zentrum Dresden-Rossendorf (HZDR), Germany + index: 1 + - name: University of Wrocław, Poland + index: 2 + - name: Max Planck Institute of Molecular Cell Biology and Genetics, Dresden, Germany + index: 3 + - name: Technische Universität Dresden, Germany + index: 4 +date: 30 September 2024 +bibliography: paper.bib +--- + +# Summary + +Interpolation is essential in various computational tasks, +including function approximation, curve fitting, numerical integration, +differential geometry, +spectral methods, optimization, +and uncertainty quantification. + +Minterpy is an open-source Python package designed +for multivariate polynomial interpolation. +It provides stable and accurate interpolating polynomials for approximating a wide range of functions. +Key features include: + +- Polynomial interpolation on properly selected nodes and + regression on arbitrary nodes. +- Differentiation and integration operations on the polynomials. +- Addition, subtraction, and multiplication operations + on the polynomials. + +Minterpy's long-term vision is to provide researchers and engineers +a software solution that mitigates the curse of dimensionality +commonly associated with interpolation tasks. + +# Statement of need + +As a means of approximating functions, global polynomials---where a single +polynomial is defined over the entire domain---offer several advantages. +For sufficiently smooth functions, global polynomials can achieve +high accuracy with a smaller number of data points (sampled over the entire domain) +compared to local piecewise polynomials. +Additionally, their relatively simple structure facilitates +many common numerical operations. +These operations include differentiation, integration, addition, subtraction, +and multiplication [@Trefethen2019]. + +The Stone-Weierstrass theorem establishes that any continuous function +on a bounded domain in multiple dimensions can be approximated uniformly +to arbitrary precision by multivariate global polynomials [@Branges1959]. +However, the theorem does not specify a concrete method for constructing +such approximating polynomials. +Various techniques can be employed to build approximating polynomials, +such as least square approximations. +Minterpy focuses on constructing approximating global polynomials using +one of the earliest and most established methods: interpolation [@Goldstine1977]. + +Polynomial interpolation is based on the principle that, in one dimension, +there exists a unique polynomial $Q_{f, n}$ of degree $n$ that interpolates +a function $f: \Omega \to \mathbb{R}$ in a bounded domain +$\Omega$ with $n + 1$ _distinct (unisolvent[^unisolvent]) interpolation nodes +(or points)_ $P_n$ such that +\begin{equation} +\label{eq:interpolation-condition} +Q_{f, n} (p_i) = f(p_i),\; \forall p_i \in P_n \subset \Omega,\; i = 0, \ldots, n. +\end{equation} +Polynomial interpolation has its roots in the works of Newton, Euler, Lagrange, +and others [@Meijering2002], and its significance in mathematics and computing +is well-established [@Cools2002;@Xiu2009]. + +Despite their aforementioned advantages as global polynomials, +global interpolating polynomials have a controversial reputation due to +several misconceptions [@Trefethen2011;@Trefethen2016;@Trefethen2017]: + +- They are often thought to be prone to Runge's phenomenon, + whereby increasing the degree of interpolating polynomials worsens + the approximation quality. +- Their evaluation is frequently believed to be numerically unstable + and susceptible to round-off errors. +- Their extension to multiple dimensions is seen as severely limited + by the curse of dimensionality, particularly when using tensor product + constructions, which causes the required number of interpolation nodes + (i.e., data points) to grow exponentially with the number of spatial dimensions. +- They are said to generally fail to converge to the approximated function + as the degree increases, with Faber's theorem often cited + to justify this assertion. + This view has contributed to a more generally pessimistic outlook + on the use of interpolating polynomials for function approximation. + +Minterpy addresses these issues by: + +- Constructing multivariate interpolating polynomials using + appropriate interpolation nodes (e.g., Chebyshev-Lobatto nodes) + to help mitigate Runge's phenomenon[^equispaced]; +- Representing the interpolating polynomials in the Newton basis, + combined with Leja ordering of the interpolation nodes + to ensure stable evaluation [@Reichel1990;@TalEzer1991;@Breuss2018]; +- Using a multi-index set to represent the multivariate polynomials, + which can be tailored to mitigate the curse of dimensionality + while preserving the approximation power of the interpolating polynomials + (more on this in the next section). + +While Faber's theorem shows that no _interpolating polynomial_ can converge +for _all_ continuous functions, it has been demonstrated that if the function +is reasonably smooth, the interpolating polynomials do converge +at high algebraic rates for common regular (Lipschitz continuous[^lipschitz]) +functions and at geometric rates for analytic functions [@Trefethen2017a]. + +Minterpy shares similar objectives and functionality with Chebfun [@Driscoll2014], +a popular MATLAB package[^chebfun-ports] designed for numerical computations +using interpolating polynomials, specifically Chebyshev polynomials. +Chebfun provides features such as root finding, differentiation, and integration +for function approximation in up to three dimensions. +In contrast, Minterpy supports higher dimensions but with fewer features. + +Several Python packages, such as Chaospy [@Feinberg2015], +equadratures [@Seshadri2017], PyGPC [@Weise2020], PyThia [@Hegemann2023], +and UncertainSci [@Tate2023], provide polynomial-based function approximations, +primarily for uncertainty quantification (UQ) using generalized polynomial +chaos expansion [@Xiu2002]. +These tools frame problems as UQ tasks, where inputs are modeled +probabilistically. +With few exceptions (notably Chaospy), the resulting polynomials are primarily +used for function approximations, accompanied by additional post-processing +utilities tailored to UQ tasks (e.g., uncertainty propagation, +sensitivity analysis). +In contrast, Minterpy offers a simpler, UQ-free approach to function approximation +using interpolating polynomials, with fewer barriers to entry, and includes +several mathematical operations on the polynomials. + +Several other Python packages construct polynomial approximations from data. +SciPy [@Virtanen2020] provides multivariate interpolation methods +(e.g., linear, nearest, pchip[^pchip]) for rectilinear grids. +ndsplines [@Margolis2019] efficiently implements tensor-product multivariate +B-splines that can be differentiated and anti-differentiated. +Unlike Minterpy, these tools rely on piecewise local polynomials +and are tailored for input/output data pairs. +Familiar and widely used, piecewise polynomials---especially splines---remain +established tools for polynomial interpolation tasks. + +In summary, while not a universal tool for all function approximation problems, +Minterpy offers a robust solution for approximating a wide range of multidimensional +Lipschitz continuous functions using accurate and stable polynomials. +Once obtained, these polynomials can be readily manipulated using standard +arithmetic operations, such as addition and multiplication, +as well as calculus operations, like differentiation and integration. +The significance of this capability extends beyond function approximation, +as many numerical methods (e.g., root finding, optimization) can be boiled down +to these fundamental operations on functions. +By leveraging Minterpy's polynomials, +users can conveniently carry out symbolic-like computations +that would normally require direct manipulation of function values. + +# Package overview + +Consider an $m$-dimensional function $f: \boldsymbol{\Omega} \subset \mathbb{R}^m \to \mathbb{R}$, +defined on a hypercube. +Minterpy interpolates the function using a polynomial expansion +in the Lagrange basis +\begin{equation} +\label{eq:interpolating-polynomial} +f (\boldsymbol{x}) \approx Q (\boldsymbol{x}) = \sum_{\boldsymbol{\alpha} \in A} f(\boldsymbol{p}_{\boldsymbol{\alpha}}) \, L_{\boldsymbol{\alpha}} (\boldsymbol{x}), +\end{equation} +where $A \subseteq \mathbb{N}^m$, +$L_{\boldsymbol{\alpha}}$, and $\boldsymbol{p}_{\boldsymbol{\alpha}}$ +are the multi-index set, +the Lagrange basis polynomial, +and the unisolvent node that correspond to the index element $\boldsymbol{\alpha}$, +respectively. +The set $\{ \boldsymbol{p}_{\boldsymbol{\alpha}} \}_{\boldsymbol{\alpha} \in A}$ +forms the interpolation grid. + +Each basis polynomial satisfies the Kronecker delta condition +$$ +L_{\boldsymbol{\alpha}} (p_{\boldsymbol{\beta}}) = \delta_{\boldsymbol{\alpha}, \boldsymbol{\beta}},\;\; p_{\boldsymbol{\beta}} \in \{ \boldsymbol{p}_{\boldsymbol{\alpha}} \}_{\boldsymbol{\alpha} \in A},\;\; \boldsymbol{\alpha} \in A, +$$ +ensuring $Q(\boldsymbol{x})$ in \autoref{eq:interpolating-polynomial} +is an interpolating polynomial. + +The multi-index set $A$ determines polynomial coefficients, unisolvent nodes, +and function evaluations. +In Minterpy, the default is a downward-closed set $A_{m, n, p}$ +with spatial dimension $m \in \mathbb{N}_{> 0}$, +polynomial degree $n \in \mathbb{N}$, and $\ell_p$-degree $p \in \mathbb{R}_{> 0}$. +The set is defined as +$$ +A_{m, n, p} = \{ \boldsymbol{\alpha} \in \mathbb{N}^m: \lVert \boldsymbol{\alpha} \rVert_p = (\alpha_1^p + \cdots + \alpha_m^p)^{1/p} \leq n \}. +$$ +Here, typical choices for $p$ are $1.0$, $2.0$, and $\infty$, +representing the total, Euclidean, and maximum degree (tensor-product), +respectively. These values for $p$ correspond to polynomial, sub-exponential, +and exponential growth of the set size as a function of the spatial dimension. +Consequently, the maximum degree set faces a severe curse of dimensionality +due to the rapid growth of the set size. + +It has been shown that the Euclidean degree $p = 2.0$ offers the best compromise +for isotropic functions (where each variable has the same importance)[^anisotropy], +as its convergence rate matches that of $p = \infty$ with respect +to the polynomial degree, yet with a significantly smaller multi-index set. +In contrast, while the size of the multi-index set for $p = 2.0$ +is larger than that for $p = 1.0$, the gain in accuracy more than compensates +for the increased cost [@Trefethen2017a;@Hecht2025]. + +Deriving multidimensional Lagrange bases for non-tensorial grids is challenging. +Minterpy uses the Newton basis for efficient evaluation and differentiation +$$ +Q (\boldsymbol{x}) = \sum_{\boldsymbol{\alpha} \in A} c_{\boldsymbol{\alpha}} \, N_{\boldsymbol{\alpha}} (\boldsymbol{x}),\;\; N_{\boldsymbol{\alpha}} (\boldsymbol{x}) = \prod_{i = 1}^m \prod_{j = 0}^{\alpha_i - 1} (x_i - q_j),\;\; q_j \in P_i, +$$ +where $c_{\boldsymbol{\alpha}}$ and $N_{\boldsymbol{\alpha}}$ are +the Newton coefficient and Newton polynomial +that correspond to the index element $\boldsymbol{\alpha}$, respectively; +$P_i$ is a set of interpolation nodes in each dimension. +Using Leja-ordered Chebyshev-Lobatto interpolation nodes by default, +Newton basis offers numerical stability [@Reichel1990;@TalEzer1991;@Breuss2018]. +Computing Newton coefficients, based on the Lagrange coefficients and interpolation grid, +via a multidimensional divided-difference scheme (DDS) is a key step +in Minterpy [@Hecht2025]. + +Minterpy also supports other polynomial bases, +including the canonical (monomial) and Chebyshev (first kind) bases, +along with transformations between them. + +## Minterpy polynomials for function approximation + +Minterpy prioritizes stable and accurate function approximation through +polynomial interpolations, even for high-degree polynomials. +Consider, the Runge function: +$$ +f(\boldsymbol{x}) = \frac{1}{1 + \lVert \boldsymbol{x} \rVert^2},\; \boldsymbol{x} \in [-1, 1]^m, +$$ +commonly used to demonstrate Runge's phenomenon, +a pitfall in high-degree interpolation with equispaced points. + +![The comparison of Minterpy interpolating polynomials, approximating the Runge function in dimension $m = 3, 4$, with alternative methods from designated packages.\label{fig:convergence}](convergence.png) + +\autoref{fig:convergence} shows the accuracy of Minterpy interpolating polynomials +for three different $\ell_p$-degrees in dimension $m = 3, 4$[^machine]. +The horizontal axis shows the number of coefficients (and function evaluations), +directly linked to the polynomial degree, to enable comparisons with other methods. +The infinity norm of the difference between the function and its approximation, +$$ +\lVert f - Q_f \rVert_{\infty} = \max_{\boldsymbol{x} \in [-1, 1]^m} \lvert f(\boldsymbol{x}) - Q_f(\boldsymbol{x}) \rvert +$$ +is measured at $1'000'000$ random points. + +The figure compares data-driven methods (SciPy v1.13.1, ndsplines v0.2.0post0) +and pseudo-spectral methods (Chaospy v4.3.18, Equadratures v10). +In the data-driven methods, approximation complexity is fixed as data increases. +While ndsplines supports higher degrees, splines above degree 5 are rare in practice. +The pseudo-spectral methods approximate functions using Legendre polynomial expansions on tensor-product grids, +with coefficients computed via numerical integration. +The coefficient count matches Minterpy interpolating polynomials with $p = \infty$. +Equadratures, whose results are comparable to Minterpy, +(softly) limits multi-index cardinality to $5 \times 10^4$ due to computational expense, +while Chaospy struggles with tensor-product grids[^sparse]. + +The results show that Minterpy polynomials provide highly accurate function approximation, +demonstrating numerical stability and convergence down to $10^{-14}$, +and outperforming selected competing tools. +However, global polynomials are generally more computationally expensive to evaluate +than local piecewise polynomials or B-splines, +as they require more floating-point operations. +There are two primary reasons for this. +First, global polynomials lack compact support; evaluating them typically involves +computing all terms (i.e., coefficient-basis function pairs) in the expansion. +Second, they often require high polynomial degrees, +resulting in a large number of terms compared to local methods, +which usually employ low-degree polynomials. +Moreover, the basis functions in a high-degree global polynomial involve +numerous multiplications, +further increasing the computational cost. + +## Operations on the Minterpy polynomials + +As mentioned, Minterpy polynomials support arithmetic operations +(addition, subtraction, multiplication) +and calculus operations (differentiation, definite integration). +Except for definite integration (yielding a numerical value), +these operations produce another polynomial, ensuring closure. +Among compared tools, only Chaospy offers similar capabilities. + +## Polynomial regression + +By default, Minterpy uses Leja-ordered Chebyshev-Lobatto nodes. +For scattered or equispaced data, it supports well-conditioned +least-squares construction [@Veettil2022]. +The resulting polynomials are Minterpy polynomials[^non-interpolatory]. + +## Applications + +Minterpy has been applied in various research fields, +including data fitting in physics [@Dornheim2023], +serving as a surrogate model in blackbox optimization [@Schreiber2023], +and representing level sets in differential geometry [@Veettil2023]. + +# Author contributions + +The contributions to this paper are listed according +to [CRediT](https://credit.niso.org). +**D. Wicaksono**: Conceptualization, software, validation, visualization, writing---original draft. +**U. Hernandez Acosta**: Conceptualization, project administration, software, writing---review & editing. +**S. K. Thekke Veettil**: Conceptualization, software. +**J. Kissinger**: Conceptualization, software. +**M. Hecht**: Conceptualization, supervision, funding acquisition, writing---review & editing. + +# Acknowledgments + +The authors express their gratitude to Michael Bussmann for his support +and suggestions; Michał Bajda for the Minterpy logo design; +and Janina Schreiber for the code review. + +The work is partly funded by the Center for Advanced Systems Understanding ([CASUS](https://www.casus.science)) +which is financed by Germany's Federal Ministry of Education and Research (BMBF) +and by the Saxony Ministry for Science, Culture and Tourism (SMWK). +Funding is provided through tax funds based on the budget approved +by the Saxony State Parliament. + +# References + +[^unisolvent]: Unisolvent here means that the interpolating polynomial +can be uniquely determined by the given interpolation nodes. +In one dimension, this implies that the nodes are of distinct values. +[^equispaced]: Runge's phenomenon arises when using equispaced interpolation +nodes, causing large oscillations, especially near the interval's endpoints. +Adding more points does not resolve these oscillations. +[^lipschitz]: that is, $\lvert f(x) - f(y) \rvert \leq L \lvert x - y \rvert$ +for some constant $L$ and for all $x, y \in \Omega$ +where $\Omega$ is a bounded domain. +[^chebfun-ports]: Packages in other languages based on or similar to Chebfun +include ApproxFun [@Olver2023] (Julia), +and ChebPy [@Richardson2024] and pychebfun [@Swierczewski2024] (Python). +[^anisotropy]: Incorporating anisotropy (e.g., via an adaptive scheme) enables +sparser polynomials. While Minterpy does not yet support adaptivity, +users can define custom downward-closed multi-index sets for interpolation. +[^machine]: Details of the numerical experiments can be found in [@Wicaksono2025]. +[^sparse]: Both Chaospy and equadratures support sparse polynomial construction, +which can help reduce the number of coefficients. +Comparing these approaches, however, is beyond the scope of this work. +[^pchip]: Piecewise cubic Hermite interpolating polynomial. +[^non-interpolatory]: The polynomials are, however, not strictly interpolatory, +i.e., they generally do not satisfy \autoref{eq:interpolation-condition}. diff --git a/setup.cfg b/setup.cfg index dc4551e4..9e590729 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ name = minterpy description = Python library for multivariate polynomial interpolation. long_description = file: README.md long_description_content_type = text/markdown -url = https://gitlab.hzdr.de/interpol/minterpy +url = https://github.com/minterpy-project/minterpy author = file: AUTHORS.md author_email = u.hernandez@hzdr.de maintainer = Minterpy development team @@ -13,9 +13,10 @@ license_file = LICENSE platforms = Any classifiers = - Development Status :: 1 - Planning + Development Status :: 4 - Beta Intended Audience :: Developers Intended Audience :: Science/Research + Intended Audience :: Education License :: OSI Approved :: MIT License Operating System :: OS Independent Programming Language :: Python @@ -23,9 +24,10 @@ classifiers = Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Topic :: Scientific/Engineering project_urls = - Bug Tracker = https://gitlab.hzdr.de/interpol/minterpy/issues + Bug Tracker = https://github.com/minterpy-project/minterpy/issues [options] packages = find: