_See all documentation for this version [here](https://tensorwaves.rtfd.io/en/0.3.7)._
💡 New features
<details>
<summary>Optimizer and Estimator type are now written to callback output (364)</summary>
`CSVSummary` was writing `"estimator_type"` incorrectly (it was writing the optimizer type). This PR fixes that and adds the optimizer type as an additional entry, also to `YAMLSummary`.
</details>
<details>
<summary>Lambdify with common sub-expressions (374)</summary>
See `cse` argument in [`sympy.lambdify()`](https://docs.sympy.org/latest/modules/utilities/lambdify.html#sympy.utilities.lambdify.lambdify). This fixes https://github.com/ComPWA/tensorwaves/pull/345#commitcomment-61398587.
Note that lambdified source code becomes significantly smaller in larger expressions. Finding common sub-expressions has a small hit in performance when lambdifying, but in larger expressions, this is overcome by the fact that the output source code is smaller.
</details>
⚠️ Interface
<details>
<summary>Sympy implementation is now isolated in a sub-module (344)</summary>
Extracted all SymPy functionality under `tensorwaves.model` into a separate sub-module `tensorwaves.model.sympy`.
</details>
<details>
<summary>Removed doit call from SympyModel (347)</summary>
Closes 280
This means that `doit()` has to be called on the expression first.
</details>
🐛 Bug fixes
<details>
<summary>Correct estimator value is now written to callback output (364)</summary>
`CSVSummary` was writing `"estimator_type"` incorrectly (it was writing the optimizer type). This PR fixes that and adds the optimizer type as an additional entry, also to `YAMLSummary`.
</details>
<details>
<summary>ComplexSqrt can now lambdified to TensorFlow as well (365)</summary>
JAX and TensorFlow printing is forwarded to the NumPy printer, but with `jax.numpy` and `tensorflow.experimental.numpy` as `Printer._module` respectively.
Other improvements:
- Extended tests for `find_function` and wrote a test for lambdifying AmpForm's `ComplexSqrt`
- Allow getting `tensorflow.Tensor` with `find_function`
- Moved `_backend` module to `function`, because `function` is most related to back-ends.
</details>
🔨 Internal maintenance
<details>
<summary>Swapped optimized_lambdify() implementation (348)</summary>
Closes 322
The role of `_backend_lambdify` and `_sympy_lambdify` is now swapped:
- `_backend_lambdify` is now purely a wrapper around `sympy.lambdify`.
- `_sympy_lambdify` offers a switch between `_backend_lambdify` and `optimized_lambdify`.
These functions will change further in 292, but this is PR focuses only on the problem describe din 322.
</details>
<details>
<summary>Unit tests and integration tests are now split (349)</summary>
All tests that require AmpForm have been seperated from proper unit tests (that require no additional dependencies). The folder structure under `tests` is now:
text
tests
├── integration
└── unit
Additional improvements:
- Fixtures for the AmpForm tests have been parametrized:
- `qrules.ReactionInfo` is parametrized with the canonica-helicity and helicity formalism.
- `SympyModel` is constructed with and without `max_complexity` argument in the constructor, so that `optimized_lambdify` is tested as well.
- Improved error message of `LambdifiedFunction.update_parameters`: over-defined parameters were computed incorrectly. In addition, the error message now prints the expected parameters.
- Callbacks can now take `pathlib.Path` (previously only `str`). This makes it possible to convert the `output_dir` fixture into a `Path` as well.
</details>
<details>
<summary>Backend handling is now isolated in a sub-module (350)</summary>
344 created a module `tensorwaves.model.backend` with the intention to collect functions that handle back-ends. This PR moves `_find_function_in_backend` (which was under `tensorwaves.estimator`) there as well, moves the module to the top, and hides it altogether, as these functions are implementation details.
</details>
<details>
<summary>Add unit tests for optimized_lambdify (351)</summary>
Additional fixes:
- The faster-lambdify notebook was failing due to the interface change introduced by 348. This was not noticed, because the `%%time` statement in the cell makes the error code of that cell return 'success'. The error has been fixed and a hidden test cell has been added to prevent such failures in the future.
- `optimized_lambdify` now directly calls `_backend_lambdify` is `max_complexity` is higher than the number of nodes in the expression.
</details>
<details>
<summary>Callback output is written to separate files in the tests (352)</summary>
Integration tests have become unstable since 349, see e.g. https://github.com/ComPWA/tensorwaves/actions/runs/1504632721, because the callback output is written to the same file when using `optimized_lambdify` / `_backend_lambdify`.
</details>
<details>
<summary>Added unit tests for fast optimize (360)</summary>
Closes 135
Adds a test under the `tests/unit` folder that fits a small model with all back-ends and optimizers plus a unit test for `generate_data`. This also helped fishing out some bugs (see [commit history](https://github.com/ComPWA/tensorwaves/pull/360/commits)).
Other improvements:
- Import optimizers directly from the `tensorwaves.optimizer` module, e.g.:
python
from tensorwaves.optimizer import Minuit2
instead of
python
from tensorwaves.optimizer.minuit import Minuit2
- CSVSummary writes estimator value as float (was complex by mistake)
- Latest function call number is also stored in `Loadable` callbacks.
- Scipy now works with TF
</details>
<details>
<summary>Importing tensorwaves is now about 8x as fast (363)</summary>
Import expensive modules inline to speed up importing `tensorwaves`. This makes `import tensorwaves` (and collecting tests) about 8x as fast. Profiling done with [tuna](https://github.com/nschloe/tuna) as follows (see [stackoverflow](https://stackoverflow.com/a/51300944)):
shell
python3 -X importtime -c "import tensorwaves" 2> tw.log && tuna tw.log
</details>
<details>
<summary>Callbacks are now not run during optimize() if unspecified (366)</summary>
Previously, if no callback was specified in the optimizer constructor, an empty CallbackList would be created and on_optimize_end etc were always called. This is (theoretically) slower.
Some other improvements:
- Use [`attrs` next-generation API](https://www.attrs.org/en/stable/api.html#next-gen) (see also https://github.com/ComPWA/compwa-org/issues/90).
- Avoid creating stream on creation of Loadable callback.
- Fail pytest on warnings (this helped fishing out the above bug)
</details>
<details>
<summary>Generalized SymPy printer implementation (371)</summary>
</details>
📝 Documentation
<details>
<summary>Added API links to FitResult.specifics (356)</summary>
Added links to the 'fit result' objects in the `iminuit` and SciPy APIs.
</details>
🖱️ Developer Experience
<details>
<summary>Pytest on GitHub Actions is now stable (355)</summary>
Fix-up to 349
Writing with a callback in a pytest fixture and then loading it back in a test led to instable CI. This PR should fix that.
</details>
<details>
<summary>Notebooks can now be run with pytest (359)</summary>
Switch from [`pytest-notebook`](https://pypi.org/project/pytest-notebook) to [`nbmake`](https://pypi.org/project/nbmake). Now it's again possible to run specific notebooks from the terminal with e.g.:
shell
pytest --nbmake docs/usage/basics.ipynb
Other small fixes:
- Avoid `fast_lambdify()` in Jupyter notebooks to speed up docs workflow.
- Cast to `tuple` in `ParametrizedBackendFunction`.
</details>
<details>
<summary>Merge test jobs on GitHub Actions (367)</summary>
Reorganise GitHub Action workflow for pytest. Extracted from 366 in order to identify potential performance issues. Notebooks slow after the changes introduced in 366, which may be caused by the changes to the callbacks.
Other changes;
- Treat warnings raised under pytest as errors.
- Renamed tox job for testing notebooks to `nb`.
</details>
<details>
<summary>Reduced dependencies in style requirements (369)</summary>
Should speed up [pre-commit job](https://github.com/ComPWA/tensorwaves/actions/workflows/ci-style.yml).
</details>
<details>
<summary>Pytest collect is now faster (370)</summary>
Import expensive modules in the tests inline so that `pytest --collect-only` is faster.
</details>