# expressive
A library for quickly applying symbolic expressions to NumPy arrays
By enabling callers to front-load sample data, developers can move the runtime cost of Numba's JIT to the application's initial loading (or an earlier build) and also avoid `exec` during runtime, which is otherwise needed when lambdifying symbolic expressions
Inspired in part by this Stack Overflow Question [Using numba.autojit on a lambdify'd sympy expression](https://stackoverflow.com/questions/22793601/using-numba-autojit-on-a-lambdifyd-sympy-expression)
## installation
via pip https://pypi.org/project/expressive/
```shell
pip install expressive
```
## usage
refer to tests for examples for now
generally follow a workflow like
* create instance `expr = Expressive("a + log(b)")`
* build instance `expr.build(sample_data)`
* instance is now callable `expr(full_data)`
The `data` should be provided as dict of NumPy arrays
```python
sample_data = { # types are used to compile a fast version for full data
"a": numpy.array([1,2,3,4], dtype="int64"),
"b": numpy.array([4,3,2,1], dtype="int64"),
}
full_data = {
"a": numpy.array(range(1_000_000), dtype="int64"),
"b": numpy.array(range(1_000_000), dtype="int64"),
}
```
## testing
Only `docker` and `docker compose` (v2) are required, and used to generate and host testing
```shell
sudo apt install docker.io docker-compose-v2 # debian/ubuntu
sudo usermod -aG docker $USER
sudo su -l $USER # login shell to self (reboot for all shells)
```
Run the test script from the root of the repository and it will build the docker test environment and run itself inside it automatically
```shell
./test/runtests.sh
```
## building
Follows the generic build and publish process
* https://packaging.python.org/en/latest/tutorials/packaging-projects/#generating-distribution-archives
* build (builder) https://pypi.org/project/build/
* twine (publisher) https://pypi.org/project/twine/
```shell
python3 -m pip install --upgrade build twine
# mv dist/* ../build-backups/ # optionally clean dist/ directory
python3 -m build
# python3 -m twine upload dist/* # to publish, ensure build succeeded
```
## contributing
The development process is currently private (though most fruits are available here!), largely due to this being my first public project with the potential for other users than myself, and so the potential for more public gaffes is far greater
Please refer to [CONTRIBUTING.md](https://gitlab.com/expressive-py/expressive/-/blob/main/CONTRIBUTING.md) and [LICENSE.txt](https://gitlab.com/expressive-py/expressive/-/blob/main/LICENSE.txt) and feel free to provide feedback, bug reports, etc. via [Issues](https://gitlab.com/expressive-py/expressive/-/issues), subject to the former
#### additional future intentions for contributing
* improve internal development history as time, popularity, and practicality allows
* move to parallel/multi-version/grid CI over all-in-1, single-version dev+test container
* greatly relax dependency version requirements to improve compatibility
## version history
##### v1.8.1
* fixed a regex bug where multidigit offset indicies could become multiplied `x[i+10]` to `x[i+1*0]`
* improve complex result type guessing
##### v1.8.0
* support for passing a SymPy expr (`Expr`, `Equality`), not just strings
##### v1.7.0
* support for passing SymPy symbols to be used
##### v1.6.1 (unreleased)
* support indexed result array filling for complex dtypes
##### v1.6.0
* complex dtypes MVP (`complex64`, `complex128`)
* parse coefficients directly adjacent to parentheses `3(x+1)` -> `3*(x+1)`
##### v1.5.1 (unreleased)
* improved README wording of [testing](#testing) and added [building section](#building)
* better messages when testing and `docker` is absent or freshly installed
##### v1.5.0
* added `._repr_html_()` method for improved display in Jupyter/IPython notebooks
##### v1.4.2
* greatly improved verify
* `numpy.allclose()` takes exactly 2 arrays to compare (further args are passed to `rtol`, `atol`)
* SymPy namespace special values `oo`, `zoo`, `nan` are coerced to NumPy equivalents (`inf`, `-inf`, `nan`)
* raise when result is `False`
* groundwork to maintain an internal collection of results
* internal symbols collection maintains `IndexedBase` instances (`e.atoms(Symbol)` returns `Symbol` instances)
* improve Exceptions from data that can't be used
* new custom warning helper for testing as `assertWarnsRegex` annoyingly eats every warning it can
##### v1.4.1
* more sensibly fill the result array for non-floats when not provided (only float supports NaN)
##### v1.4.0
* add build-time verify step to help identify math and typing issues
* some improved logic flow and improved `warn()`
##### v1.3.2 (unreleased)
* improved publishing workflow
* improved README
##### v1.3.1
* fix bad math related to indexing range
* add an integration test
##### v1.3.0
* add support for parsing equality to result
* add support for (optionally) passing result array
* hugely improve docstrings
##### v1.2.1
* add more detail to [contributing block](#contributing)
* switch array dimensions checking from `.shape` to `.ndim`
* switch tests from `numpy.array(range())` to `numpy.arange()`
##### v1.2.0
* enable autobuilding (skip explicit `.build()` call)
* basic display support for `Expressive` instances
##### v1.1.1
* add version history block
##### v1.1.0
* fixed bug: signature ordering could be unaligned with symbols, resulting in bad types
* added support for non-vector data arguments
##### v1.0.0
* completely new code tree under Apache 2 license
* basic support for indexed offsets
##### v0.2.0 (unreleased)
##### v0.1.0
* very early version with support for python 3.5
Raw data
{
"_id": null,
"home_page": "https://gitlab.com/expressive-py/expressive",
"name": "expressive",
"maintainer": "Russell Fordyce",
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "sympy numba numpy",
"author": null,
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/ae/8b/6b1db3b57960c1589cb12d654c5bc33869f1524d32869ed727c9d61edf2b/expressive-1.8.1.tar.gz",
"platform": null,
"description": "# expressive\n\nA library for quickly applying symbolic expressions to NumPy arrays\n\nBy enabling callers to front-load sample data, developers can move the runtime cost of Numba's JIT to the application's initial loading (or an earlier build) and also avoid `exec` during runtime, which is otherwise needed when lambdifying symbolic expressions\n\nInspired in part by this Stack Overflow Question [Using numba.autojit on a lambdify'd sympy expression](https://stackoverflow.com/questions/22793601/using-numba-autojit-on-a-lambdifyd-sympy-expression)\n\n## installation\n\nvia pip https://pypi.org/project/expressive/\n\n```shell\npip install expressive\n```\n\n## usage\n\nrefer to tests for examples for now\n\ngenerally follow a workflow like\n* create instance `expr = Expressive(\"a + log(b)\")`\n* build instance `expr.build(sample_data)`\n* instance is now callable `expr(full_data)`\n\nThe `data` should be provided as dict of NumPy arrays\n\n```python\nsample_data = { # types are used to compile a fast version for full data\n \"a\": numpy.array([1,2,3,4], dtype=\"int64\"),\n \"b\": numpy.array([4,3,2,1], dtype=\"int64\"),\n}\nfull_data = {\n \"a\": numpy.array(range(1_000_000), dtype=\"int64\"),\n \"b\": numpy.array(range(1_000_000), dtype=\"int64\"),\n}\n```\n\n## testing\n\nOnly `docker` and `docker compose` (v2) are required, and used to generate and host testing\n\n```shell\nsudo apt install docker.io docker-compose-v2 # debian/ubuntu\nsudo usermod -aG docker $USER\nsudo su -l $USER # login shell to self (reboot for all shells)\n```\n\nRun the test script from the root of the repository and it will build the docker test environment and run itself inside it automatically\n\n```shell\n./test/runtests.sh\n```\n\n## building\n\nFollows the generic build and publish process\n* https://packaging.python.org/en/latest/tutorials/packaging-projects/#generating-distribution-archives\n* build (builder) https://pypi.org/project/build/\n* twine (publisher) https://pypi.org/project/twine/\n\n```shell\npython3 -m pip install --upgrade build twine\n# mv dist/* ../build-backups/ # optionally clean dist/ directory\npython3 -m build\n# python3 -m twine upload dist/* # to publish, ensure build succeeded\n```\n\n## contributing\n\nThe development process is currently private (though most fruits are available here!), largely due to this being my first public project with the potential for other users than myself, and so the potential for more public gaffes is far greater\n\nPlease refer to [CONTRIBUTING.md](https://gitlab.com/expressive-py/expressive/-/blob/main/CONTRIBUTING.md) and [LICENSE.txt](https://gitlab.com/expressive-py/expressive/-/blob/main/LICENSE.txt) and feel free to provide feedback, bug reports, etc. via [Issues](https://gitlab.com/expressive-py/expressive/-/issues), subject to the former\n\n#### additional future intentions for contributing\n* improve internal development history as time, popularity, and practicality allows\n* move to parallel/multi-version/grid CI over all-in-1, single-version dev+test container\n* greatly relax dependency version requirements to improve compatibility\n\n## version history\n\n##### v1.8.1\n* fixed a regex bug where multidigit offset indicies could become multiplied `x[i+10]` to `x[i+1*0]`\n* improve complex result type guessing\n\n##### v1.8.0\n* support for passing a SymPy expr (`Expr`, `Equality`), not just strings\n\n##### v1.7.0\n* support for passing SymPy symbols to be used\n\n##### v1.6.1 (unreleased)\n* support indexed result array filling for complex dtypes\n\n##### v1.6.0\n* complex dtypes MVP (`complex64`, `complex128`)\n* parse coefficients directly adjacent to parentheses `3(x+1)` -> `3*(x+1)`\n\n##### v1.5.1 (unreleased)\n* improved README wording of [testing](#testing) and added [building section](#building)\n* better messages when testing and `docker` is absent or freshly installed\n\n##### v1.5.0\n* added `._repr_html_()` method for improved display in Jupyter/IPython notebooks\n\n##### v1.4.2\n* greatly improved verify\n * `numpy.allclose()` takes exactly 2 arrays to compare (further args are passed to `rtol`, `atol`)\n * SymPy namespace special values `oo`, `zoo`, `nan` are coerced to NumPy equivalents (`inf`, `-inf`, `nan`)\n * raise when result is `False`\n * groundwork to maintain an internal collection of results\n* internal symbols collection maintains `IndexedBase` instances (`e.atoms(Symbol)` returns `Symbol` instances)\n* improve Exceptions from data that can't be used\n* new custom warning helper for testing as `assertWarnsRegex` annoyingly eats every warning it can\n\n##### v1.4.1\n* more sensibly fill the result array for non-floats when not provided (only float supports NaN)\n\n##### v1.4.0\n* add build-time verify step to help identify math and typing issues\n* some improved logic flow and improved `warn()`\n\n##### v1.3.2 (unreleased)\n* improved publishing workflow\n* improved README\n\n##### v1.3.1\n* fix bad math related to indexing range\n* add an integration test\n\n##### v1.3.0\n* add support for parsing equality to result\n* add support for (optionally) passing result array\n* hugely improve docstrings\n\n##### v1.2.1\n* add more detail to [contributing block](#contributing)\n* switch array dimensions checking from `.shape` to `.ndim`\n* switch tests from `numpy.array(range())` to `numpy.arange()`\n\n##### v1.2.0\n* enable autobuilding (skip explicit `.build()` call)\n* basic display support for `Expressive` instances\n\n##### v1.1.1\n* add version history block\n\n##### v1.1.0\n* fixed bug: signature ordering could be unaligned with symbols, resulting in bad types\n* added support for non-vector data arguments\n\n##### v1.0.0\n\n* completely new code tree under Apache 2 license\n* basic support for indexed offsets\n\n##### v0.2.0 (unreleased)\n\n##### v0.1.0\n* very early version with support for python 3.5\n",
"bugtrack_url": null,
"license": "Apache License 2.0",
"summary": "A library for quickly applying symbolic expressions to NumPy arrays",
"version": "1.8.1",
"project_urls": {
"Homepage": "https://gitlab.com/expressive-py/expressive"
},
"split_keywords": [
"sympy",
"numba",
"numpy"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8b0a0614cdfa25bab42a4bceab2d3541b401d360ff35df8856783293f23b89f8",
"md5": "ae82658b34cc4727a8d5e83d3492c212",
"sha256": "583caa87968a0cd1d7cb435c9047ad910e404bf517a73c504d5746e7fe64027c"
},
"downloads": -1,
"filename": "expressive-1.8.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "ae82658b34cc4727a8d5e83d3492c212",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 22902,
"upload_time": "2024-12-19T12:38:19",
"upload_time_iso_8601": "2024-12-19T12:38:19.522849Z",
"url": "https://files.pythonhosted.org/packages/8b/0a/0614cdfa25bab42a4bceab2d3541b401d360ff35df8856783293f23b89f8/expressive-1.8.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ae8b6b1db3b57960c1589cb12d654c5bc33869f1524d32869ed727c9d61edf2b",
"md5": "51153d5e491e6ae07b017c4c66671ca5",
"sha256": "20381b3ffb3481b7037b07c540839950f21197686ba1168a84f75aaa42c3c8d5"
},
"downloads": -1,
"filename": "expressive-1.8.1.tar.gz",
"has_sig": false,
"md5_digest": "51153d5e491e6ae07b017c4c66671ca5",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 32676,
"upload_time": "2024-12-19T12:38:22",
"upload_time_iso_8601": "2024-12-19T12:38:22.807825Z",
"url": "https://files.pythonhosted.org/packages/ae/8b/6b1db3b57960c1589cb12d654c5bc33869f1524d32869ed727c9d61edf2b/expressive-1.8.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-19 12:38:22",
"github": false,
"gitlab": true,
"bitbucket": false,
"codeberg": false,
"gitlab_user": "expressive-py",
"gitlab_project": "expressive",
"lcname": "expressive"
}