_See all documentation for this specific version [here](https://tensorwaves.rtfd.io/en/0.4.0)._
TensorWaves [v0.4](https://tensorwaves.rtfd.io/en/0.4.x) has a more general interface than [v0.3](https://tensorwaves.rtfd.io/en/0.3.x). Major changes are the removal of the `Model` interface (#357) and generalization of the `data` module (392). This affects the way in which computational backend functions are created and the way in which hit-and-miss distributions are generated.
Some examples of syntax changes for an AmpForm `HelicityModel` (`model`):
**v0.4.x** (new)
python
create function and data transformer
from tensorwaves.function.sympy import create_parametrized_function
intensity = create_parametrized_function(
expression=model.expression.doit(),
parameters=model.parameter_defaults,
backend="jax",
)
helicity_transformer = SympyDataTransformer.from_sympy(
model.kinematic_variables, backend="numpy"
)
generate data
from tensorwaves.data import (
IntensityDistributionGenerator,
SympyDataTransformer,
TFPhaseSpaceGenerator,
TFUniformRealNumberGenerator,
)
phsp_generator = TFPhaseSpaceGenerator(
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
)
data_generator = IntensityDistributionGenerator(
domain_generator=phsp_generator,
function=intensity,
domain_transformer=helicity_transformer,
)
rng = TFUniformRealNumberGenerator(seed=0)
phsp = phsp_generator.generate(100_000, rng)
data = data_generator.generate(10_000, rng)
_Note that this works for general SymPy expressions: there is no AmpForm dependency._ See [this page](https://tensorwaves.readthedocs.io/en/0.4.x/usage.html).
**v0.3.x** (old)
python
from tensorwaves.model import LambdifiedFunction, SympyModel
create function and data transformer
sympy_model = SympyModel(
expression=model.expression.doit(),
parameters=model.parameter_defaults,
)
intensity = LambdifiedFunction(sympy_model, backend="jax")
helicity_transformer = HelicityTransformer(model.adapter)
generate data
from tensorwaves.data import TFUniformRealNumberGenerator, generate_data, generate_phsp
from tensorwaves.data.transform import HelicityTransformer
rng = TFUniformRealNumberGenerator(seed=0)
phsp = generate_phsp(
size=100_000,
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
random_generator=rng,
)
data = generate_data(
size=10_000,
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
data_transformer=helicity_transformer,
intensity=intensity,
random_generator=rng,
)
π‘ New features
<details>
<summary>Implemented chi-squared estimator (387)</summary>
Also includes improvements to the documentation of `estimator` module.
</details>
<details>
<summary>Implemented get_source_code function (378)</summary>
Closes 323
- Added a convenience function `tensorwaves.function.get_source_code()`
- Added read-only properties `function` and `argument_order` to `ParametrizedBackendFunction` (parallels `attrs`-decorated `PositionalArgumentFunction` class).
- `PositionalArgumentFunction` is now used internally in `ParametrizedBackendFunction` (simplifies its `__call__()` method).
- Symbols are not force-dummified anymore if `use_cse=False`
</details>
<details>
<summary>SciPy now works with TF (360)</summary>
</details>
<details>
<summary>Import optimizers directly from the tensorwaves.optimizer module (360)</summary>
It's now possible to do
python
from tensorwaves.optimizer import Minuit2
instead of
python
from tensorwaves.optimizer.minuit import Minuit2
</details>
β οΈ Interface
<details>
<summary>Adapted implementation to AmpForm v0.12.x (345)</summary>
Adapts the `data` module implementation so that it can work with [AmpForm v0.12.x](https://github.com/ComPWA/ampform/releases/tag/0.12.0). Closes https://github.com/ComPWA/ampform/issues/182.
Some major changes:
- Keys in a `DataSample` are now `str` only, not `int`. This means that momentum samples have keys `"p0"`, `"p1"`, etc. instead of `0`, `1`. This is in accordance with the `Symbol` names used in AmpForm's `HelicityModel.kinematic_variables`.
- Added a function `create_function()` that creates a `PositionalArgumentFunction`. This is a `Function` without parameters (compare `ParametrizedFunction`). The function and related class is used in the `DataTransformer` implementation, which doesn't need parameters.
- Data conversion can now be done with different back-ends.
</details>
<details>
<summary>Removed Model interface (357)</summary>
This PR removes the `Model` interface and related implementations. The interface was introduced with the idea to implement different types of expression trees later on (see [ADR-001](https://compwa-org.readthedocs.io/en/stable/adr/001.html)), but this seems to be a premature optimisation. For now, the `Function` interface suffices: `Function` instances can be created through specific functions.
Some major changes:
- The `Model` interface and its implementation `SympyModel` have been removed
- `tensorwaves.model` has been renamed to `tensorwaves.function`
- There is no way to use `performance_optimize()` (for nowβsee 358)
This means that the workflow becomes:
python
helicity_model: ampform.helicity.HelicityModel
function = create_parametrized_function(
expression=helicity_model.expression.doit(),
parameters=helicity_model.parameter_defaults,
backend="numpy",
)
instead of
python
model = SympyModel(
expression=helicity_model.expression.doit(),
parameters=helicity_model.parameter_defaults,
max_complexity=max_complexity,
)
function = LambdifiedFunction(model, backend="numpy")
</details>
<details>
<summary>Created ParametrizedFunction interface (353)</summary>
The existing [`Function`](https://tensorwaves.readthedocs.io/en/0.3.7/api/tensorwaves.interface.html#tensorwaves.interface.Function) interface has too many responsibilities: it (1) converts a `DataSample` to an array or tensor and (2) distinguishes parameter variables from domain variables. This worked fine so far, because `Function` was only used when optimizing, where you need to tweak those parameters. In 345 though, we need to a `Function` that only does (1), for the conversion of one `DataSample` (four-momenta) to another `DataSample` (kinematic variables) with different back-ends.
This PR creates a new [`ParametrizedFunction`](https://tensorwaves.readthedocs.io/en/latest/api/tensorwaves.interface.html#tensorwaves.interface.ParametrizeFunction) interface that does (1) and (2) and a 'bare' [`Function`](https://tensorwaves.readthedocs.io/en/latest/api/tensorwaves.interface.html#tensorwaves.interface.Function) interface that does only (1). The input and output types of the `Function` interface are generic, so that it can be used in different types of function-like interfaces.
Related changes:
- Renamed `LambdifiedFunction` to `ParametrizedBackendFunction`.
- `DataTransformer.transform()` has become a `__call__` and `DataTransformer` derives from `Function`.
- `Estimator` also derives from `Function`: it computes an estimator value for a set of parameters.
</details>
<details>
<summary>Generalized data generation interface (392)</summary>
Large refactoring of the `data` module with the aim to generalize its hit-and-miss mechanisms to general domain `DataSample` types.
Interface changes
- **Removed `generate_data()` and `generate_phsp()` façade functions.** The new way to generate phase space and hit-and-miss data samples is:
python
from tensorwaves.data import IntensityDistributionGenerator
from tensorwaves.data.phasespace import TFPhaseSpaceGenerator
from tensorwaves.data.rng import TFUniformRealNumberGenerator
intensity: Function
helicity_transformer: SympyDataTransformer
rng = TFUniformRealNumberGenerator(seed=0)
phsp_generator = TFPhaseSpaceGenerator(
initial_state_mass=3.0969,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
)
data_generator = IntensityDistributionGenerator(
domain_generator=phsp_generator,
domain_transformer=helicity_transformer,
function=intensity,
)
phsp = phsp_generator.generate(100_000, rng)
data = data_generator.generate(10_000, rng)
- `UniformRealNumberGenerator` -> `RealNumberGenerator`
- `PhaseSpaceGenerator` -> `DataGenerator`
- `PhaseSpaceGenerator.setup()` has been merged into the constructor (`DataGenerator.__init__()`) and removed from the interface.
- Split old `TFPhaseSpaceGenerator` into an _unweighted_ `TFPhaseSpaceGenerator` (implements `DataGenerator`) and a `TFWeightedPhaseSpaceGenerator` (implements `WeightedDataGenerator`). `TFPhaseSpaceGenerator` can be used instead of the old `generate_phsp()` function.
- Collected RNGs under a new sub-module `data.rng`
New features
- New interface: `DataGenerator`, which does not generate weights as opposed to `FourMomentumGenerator`.
- `IntensityDistributionGenerator`, which should be used instead of `generate_data()`
- `IdentityTransformer`, which is just the identity implementation of a `DataTransformer`.
- `NumpyUniformRNG`
</details>
<details>
<summary>Simplified public backend signatures (362)</summary>
Only accepts a single `str` now.
</details>
π Bug fixes
<details>
<summary>Latest function call number is now also stored in Loadable callbacks (360)</summary>
</details>
<details>
<summary>CSVSummary writes estimator value as float (360)</summary>
</details>
<details>
<summary>use_cse argument is now correctly forwarded (375)</summary>
Fix-up to 374
Additional fixes:
* Enforce specifying `use_cse` argument in hidden functions.
* Remove `**kwargs` from lambdify functions. This helps mypy/pyright identify whether functions calls miss certain arguments.
</details>
π¨ Internal maintenance
<details>
<summary>Set minimal versions for sympy and pyyaml dependencies (383)</summary>
`sympy.lambdify()` doesn't work when SymPy is too old.
</details>
π Documentation
<details>
<summary>Added GPU installation tips (381)</summary>
Preview here: https://tensorwaves--381.org.readthedocs.build/en/381/install.html
[![image](https://user-images.githubusercontent.com/29308176/145199806-c583ab2d-cddb-4aca-aadf-c0ca1631c746.png)](https://tensorwaves--381.org.readthedocs.build/en/381/install.html)
Additional improvements:
- Check link anchors with [`linkcheck_anchors = True`](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_anchors).
- Removed `typing-extensions` from requirements.
</details>
<details>
<summary>Illustrated binned and unbinned fit (388)</summary>
Follow-up to 387. Generalizes the documentation with more non-PWA examples.
</details>
<details>
<summary>Merged and isolated amplitude analysis notebooks (389)</summary>
All example notebooks for amplitude analysis have been isolated under [tensorwaves.rtfd.io/en/latest/amplitude-analysis](https://tensorwaves.rtfd.io/en/latest/amplitude-analysis). Examples under **usage** show more general expressions.
Note that resource-intensive examples like the Scipy fit on an amplitude model and the fit anination have been substituted with simpler examples, which should speed up CI on the docs.
Closes 379
</details>
<details>
<summary>Added tips for expression tree optimization (390)</summary>
The amplitude analysis notebook now shows how to optimize the expression tree with SymPy, so that the fit is much faster. This also allows showing a more complicated fit, with more free parameters and larger initial offset.
</details>
π±οΈ Developer Experience
<details>
<summary>Added fast optimize test (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)).
</details>
<details>
<summary>Implemented benchmark monitoring (368)</summary>
Closes 103
Large improvements to the testing suite:
- Added benchmark tests
- If run on the main branch, the results are pushed to the [](https://github.com/ComPWA/tensorwaves/tree/benchmark-results) branch with the [continuous-benchmark](https://github.com/marketplace/actions/continuous-benchmark) action.
- The performance results per commit are visualised on [compwa.github.io/tensorwaves](https://compwa.github.io/tensorwaves).
- If run on pull request, a warning will be commented on any commit that decreases performance. Example: https://github.com/ComPWA/tensorwaves/commit/b5c1f075eff9f9b9c82e52faf22acbb81865fdc6#commitcomment-61330128
- Integration tests have been removed so that there are only unit tests (coverage of the unit tests is sufficient since 351).
- Test folder structure has been simplified: `tests/unit` moved one folder up.
</details>